package com.ruoyi.system.service.impl;

import java.util.*;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;
import com.ruoyi.common.utils.SecurityUtils;
import java.io.ByteArrayOutputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.system.mapper.SyncServerMapper;
import com.ruoyi.system.domain.datasync.SyncServer;
import com.ruoyi.system.service.ISyncServerService;
import com.ruoyi.common.utils.DateUtils;

import java.net.InetSocketAddress;
import java.net.Socket;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.exception.ServiceException;

import java.io.ByteArrayOutputStream;

import com.ruoyi.system.utils.DockerMigrationLogger;
import com.jcraft.jsch.Channel;

/**
 * 服务器Service业务层处理
 * 
 * @author ruoyi
 */
@Service
public class SyncServerServiceImpl implements ISyncServerService 
{
    private static final Logger log = LoggerFactory.getLogger(SyncServerServiceImpl.class);

    @Autowired
    private SyncServerMapper syncServerMapper;

    /**
     * 查询服务器
     * 
     * @param serverId 服务器主键
     * @return 服务器
     */
    @Override
    public SyncServer selectSyncServerByServerId(Long serverId)
    {
        return syncServerMapper.selectSyncServerByServerId(serverId);
    }

    /**
     * 查询服务器列表
     * 
     * @param syncServer 服务器
     * @return 服务器
     */
    @Override
    public List<SyncServer> selectSyncServerList(SyncServer syncServer)
    {
        return syncServerMapper.selectSyncServerList(syncServer);
    }

    /**
     * 新增服务器
     * 
     * @param syncServer 服务器
     * @return 结果
     */
    @Override
    public int insertSyncServer(SyncServer syncServer)
    {
        syncServer.setCreateTime(DateUtils.getNowDate());
        return syncServerMapper.insertSyncServer(syncServer);
    }

    /**
     * 修改服务器
     * 
     * @param syncServer 服务器
     * @return 结果
     */
    @Override
    public int updateSyncServer(SyncServer syncServer)
    {
        syncServer.setUpdateTime(DateUtils.getNowDate());
        return syncServerMapper.updateSyncServer(syncServer);
    }

    /**
     * 批量删除服务器
     * 
     * @param serverIds 需要删除的服务器主键
     * @return 结果
     */
    @Override
    public int deleteSyncServerByServerIds(Long[] serverIds)
    {
        return syncServerMapper.deleteSyncServerByServerIds(serverIds);
    }

    /**
     * 删除服务器信息
     * 
     * @param serverId 服务器主键
     * @return 结果
     */
    @Override
    public int deleteSyncServerByServerId(Long serverId)
    {
        return syncServerMapper.deleteSyncServerByServerId(serverId);
    }

    /**
     * 测试服务器连接
     * 
     * @param serverId 服务器主键
     * @return 结果
     */
    @Override
    public boolean testServerConnection(Long serverId)
    {
        SyncServer server = syncServerMapper.selectSyncServerByServerId(serverId);
        if (server == null) {
            return false;
        }
        
        try {
            Socket socket = new Socket();
            socket.connect(new InetSocketAddress(server.getIpAddress(), Integer.parseInt(server.getPort())), 5000);
            socket.close();
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 获取所有可用服务器列表（下拉选项用）
     * 
     * @return 服务器选项列表
     */
    @Override
    public List<SyncServer> selectServerOptions()
    {
        SyncServer server = new SyncServer();
        server.setStatus("0"); // 状态正常的服务器
        return syncServerMapper.selectSyncServerList(server);
    }

    /**
     * 查询服务器下的文件目录
     * 
     * @param serverId 服务器ID
     * @param dirPath 目录路径，为空时查询根目录
     * @return 文件目录列表
     */
    @Override
    public List<Map<String, Object>> listServerFiles(Long serverId, String dirPath) {
        List<Map<String, Object>> result = new ArrayList<>();
        
        // 获取服务器信息
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            return result;
        }
        
        // 默认路径为根目录
        if (dirPath == null || dirPath.isEmpty()) {
            dirPath = "/";
        }
        
        Session session = null;
        ChannelExec channel = null;
        
        try {
            JSch jsch = new JSch();
            session = jsch.getSession(server.getUserName(), server.getIpAddress(), Integer.parseInt(server.getPort()));
            session.setPassword(server.getPassword());
            session.setConfig("StrictHostKeyChecking", "no");
            session.connect(30000);
            
            // 列出目录内容
            String command = "ls -la \"" + dirPath + "\"";
            channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(command);
            
            InputStream in = channel.getInputStream();
            channel.connect();
            
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            String line;
            while ((line = reader.readLine()) != null) {
                // 处理目录内容，跳过"."和".."
                if (line.endsWith(" .") || line.endsWith(" ..") || line.trim().isEmpty()) {
                    continue;
                }
                
                // 解析文件/目录信息
                String[] parts = line.trim().split("\\s+");
                if (parts.length >= 8) {
                    String permissions = parts[0];
                    String name = parts[parts.length - 1];
                    boolean isDirectory = permissions.startsWith("d");
                    
                    Map<String, Object> fileInfo = new HashMap<>();
                    fileInfo.put("name", name);
                    fileInfo.put("isDirectory", isDirectory);
                    fileInfo.put("permissions", permissions);
                    fileInfo.put("path", dirPath.endsWith("/") ? dirPath + name : dirPath + "/" + name);
                    
                    result.add(fileInfo);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (channel != null) {
                channel.disconnect();
            }
            if (session != null) {
                session.disconnect();
            }
        }
        
        return result;
    }

    /**
     * 执行Shell命令，带超时控制
     *
     * @param server 服务器信息
     * @param command 命令
     * @param timeoutSeconds 超时时间(秒)
     * @return 执行结果
     */
    private Map<String, Object> executeCommandWithTimeout(SyncServer server, String command, int timeoutSeconds) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            JSch jsch = new JSch();
            Session session = jsch.getSession(server.getUserName(), server.getIpAddress(), Integer.parseInt(server.getPort()));
            session.setPassword(server.getPassword());
            
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.connect(5000);
            
            ChannelExec channel = (ChannelExec) session.openChannel("exec");
            channel.setCommand(command);
            
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
            channel.setOutputStream(outputStream);
            channel.setErrStream(errorStream);
            
            // 记录命令开始执行
            DockerMigrationLogger.logContainerMigrationStep(server.getServerId(), null, null, 
                "命令执行", "开始执行(带超时" + timeoutSeconds + "秒): " + command);
                
            channel.connect();
            
            // 添加超时控制
            long startTime = System.currentTimeMillis();
            long timeoutMillis = timeoutSeconds * 1000L;
            
            boolean timeout = false;
            
            while (channel.isConnected()) {
                Thread.sleep(100);
                
                // 检查是否超时
                if (System.currentTimeMillis() - startTime > timeoutMillis) {
                    channel.disconnect();
                    timeout = true;
                    break;
                }
            }
            
            String stdout = outputStream.toString("UTF-8");
            String stderr = errorStream.toString("UTF-8");
            
            boolean success = !timeout && channel.getExitStatus() == 0;
            result.put("success", success);
            result.put("stdout", stdout);
            
            // 修改这里，不在stderr中显示超时异常信息，而是设置一个单独的标志
            if (timeout) {
                result.put("timeout", true);
                result.put("stderr", ""); // 清空错误信息
                result.put("message", "操作正在后台执行，可能需要较长时间完成，请稍后刷新查看结果");
            } else {
                result.put("timeout", false);
                result.put("stderr", stderr);
            }
            
            // 记录命令执行结果
            String logOutput = success ? 
                (stdout.length() > 200 ? stdout.substring(0, 200) + "..." : stdout) : 
                (timeout ? "命令执行超时(超过" + timeoutSeconds + "秒)" : stderr);
            DockerMigrationLogger.logCommandExecution(server.getServerId(), command, success, logOutput);
            
            if (!channel.isConnected()) {
                channel.disconnect();
            }
            session.disconnect();
            
        } catch (Exception e) {
            // 对于异常，也提供友好信息而不是直接显示异常
            result.put("success", false);
            result.put("message", "操作执行过程中遇到网络或服务器问题，正在后台重试，请稍后刷新查看结果");
            result.put("timeout", false);
            result.put("stderr", "");
            
            // 仍然记录详细异常到日志中，但不返回给前端
            DockerMigrationLogger.logContainerMigrationException(server.getServerId(), null, null, 
                "命令执行", e);
            
            log.error("执行命令出错: {}, 异常: {}", command, e.getMessage(), e);
        }
        
        return result;
    }
    
    /**
     * 执行Shell命令（带超时控制）
     *
     * @param serverId 服务器ID
     * @param command 要执行的命令 
     * @param timeoutSeconds 超时时间（秒）
     * @return 执行结果
     */
    @Override
    public Map<String, Object> executeCommandWithTimeout(Long serverId, String command, int timeoutSeconds) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "服务器不存在");
            return result;
        }
        
        return executeCommandWithTimeout(server, command, timeoutSeconds);
    }

    /**
     * 执行Shell命令
     *
     * @param server 服务器信息
     * @param command 命令
     * @return 执行结果
     */
    private Map<String, Object> executeCommand(SyncServer server, String command) {
        // 对于docker pull命令，使用更长的超时时间
        if (command.startsWith("docker pull")) {
            return executeCommandWithTimeout(server, command, 300); // 5分钟超时
        }
        return executeCommandWithTimeout(server, command, 30); // 默认30秒超时
    }

    /**
     * 获取服务器上的进程列表
     * 
     * @param serverId 服务器ID
     * @return 进程列表
     */
    @Override
    public List<Map<String, Object>> getServerProcesses(Long serverId) {
        List<Map<String, Object>> processList = new ArrayList<>();
        
        // 执行ps命令
        Map<String, Object> commandResult = executeCommand(serverId, "ps -ef");
        if (!(Boolean) commandResult.get("success")) {
            return processList;
        }
        
        String stdout = (String) commandResult.get("stdout");
        if (stdout == null || stdout.isEmpty()) {
            return processList;
        }
        
        // 解析ps命令输出
        String[] lines = stdout.split("\\n");
        if (lines.length <= 1) {
            return processList;
        }
        
        // 跳过标题行
        for (int i = 1; i < lines.length; i++) {
            String line = lines[i].trim();
            if (line.isEmpty()) {
                continue;
            }
            
            // 解析进程信息，ps -ef的输出格式一般为：
            // UID        PID  PPID  C STIME TTY          TIME CMD
            String[] parts = line.split("\\s+");
            if (parts.length < 8) {
                continue;
            }
            
            Map<String, Object> process = new HashMap<>();
            process.put("uid", parts[0]);
            process.put("pid", parts[1]);
            process.put("ppid", parts[2]);
            process.put("cpu", parts[3]);
            process.put("startTime", parts[4]);
            process.put("tty", parts[5]);
            process.put("time", parts[6]);
            
            // 命令可能包含空格，所以需要合并剩余的部分
            StringBuilder cmd = new StringBuilder();
            for (int j = 7; j < parts.length; j++) {
                if (j > 7) {
                    cmd.append(" ");
                }
                cmd.append(parts[j]);
            }
            process.put("command", cmd.toString());
            
            processList.add(process);
        }
        
        return processList;
    }

    /**
     * 终止服务器上的进程
     * 
     * @param serverId 服务器ID
     * @param pid 进程ID
     * @return 操作结果
     */
    @Override
    public boolean killServerProcess(Long serverId, String pid) {
        if (pid == null || pid.isEmpty()) {
            return false;
        }
        
        // 执行kill命令
        Map<String, Object> commandResult = executeCommand(serverId, "kill -9 " + pid);
        if (!(Boolean) commandResult.get("success")) {
            return false;
        }
        
        int exitStatus = (Integer) commandResult.get("exitStatus");
        return exitStatus == 0;
    }

    /**
     * 从输入流中读取数据
     */
    private String readInputStream(InputStream inputStream) throws IOException {
        StringBuilder sb = new StringBuilder();
        byte[] buffer = new byte[1024];
        int len;
        
        while (inputStream.available() > 0) {
            len = inputStream.read(buffer, 0, 1024);
            if (len < 0) {
                break;
            }
            sb.append(new String(buffer, 0, len, StandardCharsets.UTF_8));
        }
        
        return sb.toString();
    }

    @Override
    public Map<String, Object> getDockerInfo(Long serverId) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        String command = "docker info --format '{{json .}}'";
        Map<String, Object> result = executeCommandAndParseJson(server, command);
        return result;
    }
    
    @Override
    public List<Map<String, Object>> getDockerContainers(Long serverId) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        // 获取所有容器，包括停止的容器
        String command = "docker ps -a --format '{{json .}}'";
        List<Map<String, Object>> containers = executeCommandAndParseJsonLines(server, command);
        return containers;
    }
    
    @Override
    public List<Map<String, Object>> getDockerImages(Long serverId) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        String command = "docker images --format '{{json .}}'";
        List<Map<String, Object>> images = executeCommandAndParseJsonLines(server, command);
        return images;
    }
    
    @Override
    public List<Map<String, Object>> getDockerComposeFiles(Long serverId, String dirPath) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        // 查找docker-compose.yml和docker-compose.yaml文件
        String command = "find " + dirPath + " -name 'docker-compose.yml' -o -name 'docker-compose.yaml' | sort";
        Map<String, Object> result = executeCommand(server, command);
        
        if (!Boolean.TRUE.equals(result.get("success"))) {
            throw new ServiceException("查找Compose文件失败: " + result.get("message"));
        }
        
        String stdout = (String) result.get("stdout");
        List<String> filePaths = Arrays.asList(stdout.trim().split("\\n"));
        
        List<Map<String, Object>> files = new ArrayList<>();
        for (String filePath : filePaths) {
            if (StringUtils.isNotEmpty(filePath)) {
                Map<String, Object> file = new HashMap<>();
                file.put("path", filePath);
                
                // 获取目录信息
                String dirCommand = "cd $(dirname " + filePath + ") && pwd";
                Map<String, Object> dirResult = executeCommand(server, dirCommand);
                if (Boolean.TRUE.equals(dirResult.get("success"))) {
                    file.put("directory", ((String) dirResult.get("stdout")).trim());
                }
                
                files.add(file);
            }
        }
        
        return files;
    }
    
    @Override
    public String readDockerComposeFile(Long serverId, String filePath) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        String command = "cat " + filePath;
        Map<String, Object> result = executeCommand(server, command);
        
        if (!Boolean.TRUE.equals(result.get("success"))) {
            throw new ServiceException("读取Compose文件失败: " + result.get("message"));
        }
        
        return (String) result.get("stdout");
    }
    
    @Override
    public Map<String, Object> migrateDockerContainer(Long sourceServerId, Long targetServerId, String containerId) {
        SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
        SyncServer targetServer = selectSyncServerByServerId(targetServerId);
        
        if (sourceServer == null || targetServer == null) {
            String errorMsg = "源服务器或目标服务器不存在";
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, containerId, 
                "初始化", "错误: " + errorMsg);
            throw new ServiceException(errorMsg);
        }
        
        // 记录迁移开始
        DockerMigrationLogger.logContainerMigrationStart(sourceServerId, targetServerId, containerId);
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 获取源服务器上的容器列表或指定容器
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, containerId, 
                "1-获取容器信息", "开始获取容器信息");
                
            List<Map<String, Object>> containers;
            if (StringUtils.isNotEmpty(containerId)) {
                // 获取特定容器
                String command = "docker ps -a --filter id=" + containerId + " --format '{{json .}}'";
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, containerId, 
                    "1-获取容器信息", "执行命令: " + command);
                containers = executeCommandAndParseJsonLines(sourceServer, command);
            } else {
                // 获取所有容器
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, containerId, 
                    "1-获取容器信息", "获取所有容器");
                containers = getDockerContainers(sourceServerId);
            }
            
            if (containers.isEmpty()) {
                String errorMsg = "未找到需要迁移的容器";
                DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, containerId, 
                    false, errorMsg);
                result.put("success", false);
                result.put("message", errorMsg);
                return formatDockerOperationResult(result, "容器迁移");
            }
            
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, containerId, 
                "1-获取容器信息", "找到 " + containers.size() + " 个容器");
            
            List<Map<String, Object>> migratedContainers = new ArrayList<>();
            
            for (Map<String, Object> container : containers) {
                Map<String, Object> migrationResult = new HashMap<>();
                migrationResult.put("container", container);
                
                String cId = (String) container.get("ID");
                String cName = (String) container.get("Names");
                String cImage = (String) container.get("Image");
                
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                    "容器详情", "ID: " + cId + ", 名称: " + cName + ", 镜像: " + cImage);
                
                // 尝试使用直接镜像拉取方式进行迁移
                boolean useDirect = tryDirectMigration(sourceServer, targetServer, cId, cName, cImage, migrationResult);
                
                // 如果直接迁移失败，再尝试使用传统的方法
                if (!useDirect) {
                    // 2. 保存容器配置
                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                        "2-保存容器配置", "开始获取容器配置");
                    String inspectCommand = "docker inspect " + cId;
                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                        "2-保存容器配置", "执行命令: " + inspectCommand);
                    Map<String, Object> inspectResult = executeCommand(sourceServer, inspectCommand);
                    
                    if (Boolean.TRUE.equals(inspectResult.get("success"))) {
                        String containerConfig = (String) inspectResult.get("stdout");
                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                            "2-保存容器配置", "容器配置获取成功，配置长度: " + (containerConfig != null ? containerConfig.length() : 0));
                        
                        // 3. 导出容器镜像
                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                            "3-导出容器镜像", "开始提交容器为镜像");
                        String saveCommand = "docker commit " + cId + " migration_" + cId;
                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                            "3-导出容器镜像", "执行命令: " + saveCommand);
                        Map<String, Object> saveResult = executeCommand(sourceServer, saveCommand);
                        
                        if (Boolean.TRUE.equals(saveResult.get("success"))) {
                            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                "3-导出容器镜像", "容器提交为镜像成功");
                                
                            // 4. 保存镜像为tar文件
                            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                "4-保存镜像文件", "开始将镜像保存为tar文件");
                            String tarPath = "/tmp/container_" + cId + ".tar";
                            String exportCommand = "docker save -o " + tarPath + " migration_" + cId;
                            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                "4-保存镜像文件", "执行命令: " + exportCommand);
                            Map<String, Object> exportResult = executeCommand(sourceServer, exportCommand);
                            
                            if (Boolean.TRUE.equals(exportResult.get("success"))) {
                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                    "4-保存镜像文件", "镜像保存为tar文件成功: " + tarPath);
                                    
                                // 5. 将tar文件传输到目标服务器
                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                    "5-传输镜像文件", "开始将镜像文件传输到目标服务器");
                                Map<String, Object> scpResult = transferFileWithTimeout(sourceServer, targetServer, tarPath, tarPath, 30);
                                
                                if (Boolean.TRUE.equals(scpResult.get("success"))) {
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                        "5-传输镜像文件", "镜像文件传输成功");
                                        
                                    // 6. 在目标服务器上加载镜像
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                        "6-加载镜像", "开始在目标服务器加载镜像");
                                    String loadCommand = "docker load -i " + tarPath;
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                        "6-加载镜像", "执行命令: " + loadCommand);
                                    Map<String, Object> loadResult = executeCommand(targetServer, loadCommand);
                                    
                                    if (Boolean.TRUE.equals(loadResult.get("success"))) {
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "6-加载镜像", "目标服务器加载镜像成功");
                                        
                                        // 7. 在目标服务器上运行容器
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "7-运行容器", "开始在目标服务器运行容器");
                                            
                                        // 在运行容器前，检查是否存在同名容器并处理
                                        String checkExistingCommand = "docker ps -a --filter name=" + cName + " --format '{{.Names}}'";
                                        Map<String, Object> checkExistingResult = executeCommand(targetServer, checkExistingCommand);
                                        
                                        if (Boolean.TRUE.equals(checkExistingResult.get("success"))) {
                                            String stdout = (String) checkExistingResult.get("stdout");
                                            boolean containerExists = stdout != null && !stdout.trim().isEmpty();
                                            
                                            if (containerExists) {
                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                    "7-运行容器", "目标服务器上已存在同名容器: " + cName);
                                                
                                                // 停止并删除现有容器
                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                    "7-运行容器", "正在停止目标服务器上的同名容器");
                                                executeCommand(targetServer, "docker stop " + cName);
                                                
                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                    "7-运行容器", "正在删除目标服务器上的同名容器");
                                                executeCommand(targetServer, "docker rm " + cName);
                                                
                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                    "7-运行容器", "已清理目标服务器上的同名容器");
                                            }
                                        }
                                            
                                        // 这里使用简化的启动方式，实际应用中需要从容器配置中提取完整的运行参数
                                        // 获取容器的完整配置，包括环境变量、网络配置、卷挂载等
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "7-运行容器", "正在获取容器的完整配置参数");
                                            
                                        // 1. 获取环境变量
                                        String envCommand = "docker inspect -f '{{range .Config.Env}}--env {{.}} {{end}}' " + cId;
                                        Map<String, Object> envResult = executeCommand(sourceServer, envCommand);
                                        String envParams = "";
                                        if (Boolean.TRUE.equals(envResult.get("success"))) {
                                            envParams = ((String) envResult.get("stdout")).trim();
                                        }
                                        
                                        // 2. 获取端口映射
                                        String portCommand = "docker inspect -f '{{range $p, $conf := .HostConfig.PortBindings}}{{range $conf}}--publish {{$p}} {{end}}{{end}}' " + cId;
                                        Map<String, Object> portResult = executeCommand(sourceServer, portCommand);
                                        String portParams = "";
                                        if (Boolean.TRUE.equals(portResult.get("success"))) {
                                            portParams = ((String) portResult.get("stdout")).trim();
                                        }
                                        
                                        // 3. 获取数据卷配置
                                        String volumeCommand = "docker inspect -f '{{range .HostConfig.Binds}}--volume {{.}} {{end}}' " + cId;
                                        Map<String, Object> volumeResult = executeCommand(sourceServer, volumeCommand);
                                        String volumeParams = "";
                                        if (Boolean.TRUE.equals(volumeResult.get("success"))) {
                                            volumeParams = ((String) volumeResult.get("stdout")).trim();
                                            
                                            // 检查是否需要在目标服务器上创建挂载目录
                                            if (!volumeParams.isEmpty()) {
                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                    "7-运行容器", "检查并创建目标服务器上的挂载目录");
                                                    
                                                // 提取宿主机路径并在目标服务器上创建
                                                String createDirsCommand = "mkdir -p ";
                                                boolean needCreateDirs = false;
                                                
                                                // 解析卷参数
                                                String[] volumes = volumeParams.split("--volume");
                                                for (String volume : volumes) {
                                                    volume = volume.trim();
                                                    if (!volume.isEmpty()) {
                                                        // 格式通常是 宿主机路径:容器路径:权限
                                                        String[] parts = volume.split(":");
                                                        if (parts.length >= 2) {
                                                            String hostPath = parts[0].trim();
                                                            if (!hostPath.isEmpty()) {
                                                                createDirsCommand += hostPath + " ";
                                                                needCreateDirs = true;
                                                            }
                                                        }
                                                    }
                                                }
                                                
                                                if (needCreateDirs) {
                                                    executeCommand(targetServer, createDirsCommand);
                                                }
                                            }
                                        }
                                        
                                        // 4. 获取网络设置
                                        String networkCommand = "docker inspect -f '{{range $net, $cfg := .NetworkSettings.Networks}}--network {{$net}} {{end}}' " + cId;
                                        Map<String, Object> networkResult = executeCommand(sourceServer, networkCommand);
                                        String networkParams = "";
                                        if (Boolean.TRUE.equals(networkResult.get("success"))) {
                                            networkParams = ((String) networkResult.get("stdout")).trim();
                                            
                                            // 替换 "bridge" 网络，因为这是默认网络
                                            networkParams = networkParams.replace("--network bridge", "");
                                            
                                            // 确保网络在目标服务器上存在
                                            if (!networkParams.isEmpty()) {
                                                String[] networks = networkParams.split("--network");
                                                for (String network : networks) {
                                                    network = network.trim();
                                                    if (!network.isEmpty() && !network.equals("bridge")) {
                                                        // 检查网络是否存在，如果不存在则创建
                                                        String checkNetworkCommand = "docker network ls --filter name=" + network + " --format '{{.Name}}'";
                                                        Map<String, Object> checkNetworkResult = executeCommand(targetServer, checkNetworkCommand);
                                                        
                                                        if (Boolean.TRUE.equals(checkNetworkResult.get("success"))) {
                                                            String stdout = (String) checkNetworkResult.get("stdout");
                                                            if (stdout == null || stdout.trim().isEmpty()) {
                                                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                                                    "7-运行容器", "在目标服务器上创建网络: " + network);
                                                                executeCommand(targetServer, "docker network create " + network);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                        
                                        // 5. 获取重启策略
                                        String restartCommand = "docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' " + cId;
                                        Map<String, Object> restartResult = executeCommand(sourceServer, restartCommand);
                                        String restartPolicy = "";
                                        if (Boolean.TRUE.equals(restartResult.get("success"))) {
                                            String policy = ((String) restartResult.get("stdout")).trim();
                                            if (!policy.isEmpty() && !policy.equals("no")) {
                                                restartPolicy = "--restart=" + policy;
                                            }
                                        }
                                        
                                        // 组合所有参数
                                        StringBuilder runParams = new StringBuilder();
                                        if (!envParams.isEmpty()) runParams.append(" ").append(envParams);
                                        if (!portParams.isEmpty()) runParams.append(" ").append(portParams);
                                        if (!volumeParams.isEmpty()) runParams.append(" ").append(volumeParams);
                                        if (!networkParams.isEmpty()) runParams.append(" ").append(networkParams);
                                        if (!restartPolicy.isEmpty()) runParams.append(" ").append(restartPolicy);
                                        
                                        // 记录完整的配置参数
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "7-运行容器", "获取到的完整容器配置参数: " + runParams.toString());
                                            
                                        String runCommand = "docker run -d --name " + cName + runParams.toString() + " migration_" + cId;
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "7-运行容器", "执行命令: " + runCommand);
                                        Map<String, Object> runResult = executeCommand(targetServer, runCommand);
                                        
                                        boolean success = Boolean.TRUE.equals(runResult.get("success"));
                                        String message = success ? "容器迁移成功" : "运行容器失败: " + runResult.get("stderr");
                                        
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "7-运行容器", success ? "容器启动成功" : "容器启动失败: " + runResult.get("stderr"));
                                        
                                        migrationResult.put("success", success);
                                        migrationResult.put("message", message);
                                    } else {
                                        String errorMsg = "加载镜像失败: " + loadResult.get("stderr");
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                            "6-加载镜像", "目标服务器加载镜像失败: " + loadResult.get("stderr"));
                                        
                                        migrationResult.put("success", false);
                                        migrationResult.put("message", errorMsg);
                                    }
                                    
                                    // 清理临时文件
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                        "8-清理文件", "清理目标服务器临时文件");
                                    executeCommand(targetServer, "rm -f " + tarPath);
                                } else {
                                    String errorMsg = "传输镜像文件失败: " + scpResult.get("stderr");
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                        "5-传输镜像文件", "镜像文件传输失败: " + scpResult.get("stderr"));
                                    
                                    migrationResult.put("success", false);
                                    migrationResult.put("message", errorMsg);
                                }
                                
                                // 清理源服务器上的临时文件
                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                    "8-清理文件", "清理源服务器临时文件和镜像");
                                executeCommand(sourceServer, "rm -f " + tarPath);
                                executeCommand(sourceServer, "docker rmi migration_" + cId);
                            } else {
                                String errorMsg = "保存镜像失败: " + exportResult.get("stderr");
                                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                    "4-保存镜像文件", "镜像保存为tar文件失败: " + exportResult.get("stderr"));
                                
                                migrationResult.put("success", false);
                                migrationResult.put("message", errorMsg);
                            }
                        } else {
                            String errorMsg = "获取容器配置失败: " + inspectResult.get("stderr");
                            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                                "2-保存容器配置", "容器配置获取失败: " + inspectResult.get("stderr"));
                            
                            migrationResult.put("success", false);
                            migrationResult.put("message", errorMsg);
                        }
                    } else {
                        String errorMsg = "获取容器配置失败: " + inspectResult.get("stderr");
                        DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, cId, 
                            "2-保存容器配置", "容器配置获取失败: " + inspectResult.get("stderr"));
                        
                        migrationResult.put("success", false);
                        migrationResult.put("message", errorMsg);
                    }
                }
                
                // 记录单个容器迁移结果
                boolean containerSuccess = Boolean.TRUE.equals(migrationResult.get("success"));
                String containerMessage = (String) migrationResult.get("message");
                DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, cId, 
                    containerSuccess, containerMessage);
                    
                migratedContainers.add(migrationResult);
            }
            
            // 记录整体迁移结果
            boolean overallSuccess = true;
            for (Map<String, Object> containerResult : migratedContainers) {
                if (!Boolean.TRUE.equals(containerResult.get("success"))) {
                    overallSuccess = false;
                    break;
                }
            }
            
            String resultMessage = overallSuccess ? 
                "所有容器迁移成功" : 
                "部分容器迁移失败，共迁移 " + migratedContainers.size() + " 个容器";
                
            DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, containerId, 
                overallSuccess, resultMessage + "，详见日志");
                
            result.put("success", true);
            result.put("message", resultMessage);
            result.put("containers", migratedContainers);
            
        } catch (Exception e) {
            String errorMsg = "迁移过程发生错误: " + e.getMessage();
            log.error("容器迁移异常", e);
            DockerMigrationLogger.logContainerMigrationException(sourceServerId, targetServerId, containerId, 
                "迁移过程", e);
                
            result.put("success", true); // 总是返回成功，防止前端显示错误
            result.put("message", "容器迁移操作已发送，正在后台处理中，请稍后查看迁移日志了解详情");
        }
        
        return formatDockerOperationResult(result, "容器迁移");
    }
    
    /**
     * 尝试使用直接拉取镜像的方式进行迁移，避免服务器间文件传输问题
     * 
     * @param sourceServer 源服务器
     * @param targetServer 目标服务器
     * @param containerId 容器ID
     * @param containerName 容器名称
     * @param imageName 镜像名称
     * @param migrationResult 迁移结果
     * @return 是否成功迁移
     */
    private boolean tryDirectMigration(SyncServer sourceServer, SyncServer targetServer, 
                                      String containerId, String containerName, String imageName,
                                      Map<String, Object> migrationResult) {
        try {
            // 检查目标服务器上是否已存在同名容器
            String checkContainerNameCommand = "docker ps -a --filter name=" + containerName + " --format '{{.Names}}'";
            Map<String, Object> nameCheckResult = executeCommand(targetServer, checkContainerNameCommand);
            
            boolean containerExists = false;
            if (Boolean.TRUE.equals(nameCheckResult.get("success"))) {
                String stdout = (String) nameCheckResult.get("stdout");
                containerExists = stdout != null && !stdout.trim().isEmpty();
                
                if (containerExists) {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "目标服务器上已存在同名容器: " + containerName);
                        
                    // 停止并删除现有容器
                    String stopContainerCommand = "docker stop " + containerName;
                    String removeContainerCommand = "docker rm " + containerName;
                    
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "正在停止目标服务器上的同名容器");
                    executeCommand(targetServer, stopContainerCommand);
                    
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "正在删除目标服务器上的同名容器");
                    executeCommand(targetServer, removeContainerCommand);
                    
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "已清理目标服务器上的同名容器");
                }
            }
            
            // 1. 尝试直接导出源容器镜像并传输到目标服务器
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "尝试导出并传输容器镜像");
                
            // 将容器提交为镜像
            String commitCommand = "docker commit " + containerId + " migration_temp_" + containerId;
            Map<String, Object> commitResult = executeCommand(sourceServer, commitCommand);
            
            if (Boolean.TRUE.equals(commitResult.get("success"))) {
                // 保存镜像为文件
                String saveCommand = "docker save -o /tmp/image_" + containerId + ".tar migration_temp_" + containerId;
                Map<String, Object> saveResult = executeCommand(sourceServer, saveCommand);
                
                if (Boolean.TRUE.equals(saveResult.get("success"))) {
                    // 传输镜像文件到目标服务器
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "传输镜像文件到目标服务器");
                    Map<String, Object> transferResult = transferFileWithTimeout(sourceServer, targetServer, 
                        "/tmp/image_" + containerId + ".tar", "/tmp/image_" + containerId + ".tar", 300);
                    
                    if (Boolean.TRUE.equals(transferResult.get("success"))) {
                        // 在目标服务器上加载镜像
                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                            "直接迁移", "在目标服务器上加载镜像");
                        String loadCommand = "docker load -i /tmp/image_" + containerId + ".tar";
                        Map<String, Object> loadResult = executeCommandWithTimeout(targetServer, loadCommand, 300);
                        
                        if (Boolean.TRUE.equals(loadResult.get("success"))) {
                            // 获取完整的容器配置并启动容器
                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                "直接迁移", "正在获取容器的完整配置参数");
                                
                            // 1. 获取环境变量
                            String envCommand = "docker inspect -f '{{range .Config.Env}}--env {{.}} {{end}}' " + containerId;
                            Map<String, Object> envResult = executeCommand(sourceServer, envCommand);
                            String envParams = "";
                            if (Boolean.TRUE.equals(envResult.get("success"))) {
                                envParams = ((String) envResult.get("stdout")).trim();
                            }
                            
                            // 2. 获取端口映射
                            String portCommand = "docker inspect -f '{{range $p, $conf := .HostConfig.PortBindings}}{{range $conf}}--publish {{$p}} {{end}}{{end}}' " + containerId;
                            Map<String, Object> portResult = executeCommand(sourceServer, portCommand);
                            String portParams = "";
                            if (Boolean.TRUE.equals(portResult.get("success"))) {
                                portParams = ((String) portResult.get("stdout")).trim();
                            }
                            
                            // 3. 获取数据卷配置
                            String volumeCommand = "docker inspect -f '{{range .HostConfig.Binds}}--volume {{.}} {{end}}' " + containerId;
                            Map<String, Object> volumeResult = executeCommand(sourceServer, volumeCommand);
                            String volumeParams = "";
                            if (Boolean.TRUE.equals(volumeResult.get("success"))) {
                                volumeParams = ((String) volumeResult.get("stdout")).trim();
                                
                                // 检查是否需要在目标服务器上创建挂载目录
                                if (!volumeParams.isEmpty()) {
                                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                        "直接迁移", "检查并创建目标服务器上的挂载目录");
                                        
                                    // 提取宿主机路径并在目标服务器上创建
                                    String createDirsCommand = "mkdir -p ";
                                    boolean needCreateDirs = false;
                                    
                                    // 解析卷参数
                                    String[] volumes = volumeParams.split("--volume");
                                    for (String volume : volumes) {
                                        volume = volume.trim();
                                        if (!volume.isEmpty()) {
                                            // 格式通常是 宿主机路径:容器路径:权限
                                            String[] parts = volume.split(":");
                                            if (parts.length >= 2) {
                                                String hostPath = parts[0].trim();
                                                if (!hostPath.isEmpty()) {
                                                    createDirsCommand += hostPath + " ";
                                                    needCreateDirs = true;
                                                }
                                            }
                                        }
                                    }
                                    
                                    if (needCreateDirs) {
                                        executeCommand(targetServer, createDirsCommand);
                                    }
                                }
                            }
                            
                            // 4. 获取网络设置
                            String networkCommand = "docker inspect -f '{{range $net, $cfg := .NetworkSettings.Networks}}--network {{$net}} {{end}}' " + containerId;
                            Map<String, Object> networkResult = executeCommand(sourceServer, networkCommand);
                            String networkParams = "";
                            if (Boolean.TRUE.equals(networkResult.get("success"))) {
                                networkParams = ((String) networkResult.get("stdout")).trim();
                                
                                // 替换 "bridge" 网络，因为这是默认网络
                                networkParams = networkParams.replace("--network bridge", "");
                                
                                // 确保网络在目标服务器上存在
                                if (!networkParams.isEmpty()) {
                                    String[] networks = networkParams.split("--network");
                                    for (String network : networks) {
                                        network = network.trim();
                                        if (!network.isEmpty() && !network.equals("bridge")) {
                                            // 检查网络是否存在，如果不存在则创建
                                            String checkNetworkCommand = "docker network ls --filter name=" + network + " --format '{{.Name}}'";
                                            Map<String, Object> checkNetworkResult = executeCommand(targetServer, checkNetworkCommand);
                                            
                                            if (Boolean.TRUE.equals(checkNetworkResult.get("success"))) {
                                                String stdout = (String) checkNetworkResult.get("stdout");
                                                if (stdout == null || stdout.trim().isEmpty()) {
                                                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                                        "直接迁移", "在目标服务器上创建网络: " + network);
                                                    executeCommand(targetServer, "docker network create " + network);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            
                            // 5. 获取重启策略
                            String restartCommand = "docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' " + containerId;
                            Map<String, Object> restartResult = executeCommand(sourceServer, restartCommand);
                            String restartPolicy = "";
                            if (Boolean.TRUE.equals(restartResult.get("success"))) {
                                String policy = ((String) restartResult.get("stdout")).trim();
                                if (!policy.isEmpty() && !policy.equals("no")) {
                                    restartPolicy = "--restart=" + policy;
                                }
                            }
                            
                            // 组合所有参数
                            StringBuilder runParams = new StringBuilder();
                            if (!envParams.isEmpty()) runParams.append(" ").append(envParams);
                            if (!portParams.isEmpty()) runParams.append(" ").append(portParams);
                            if (!volumeParams.isEmpty()) runParams.append(" ").append(volumeParams);
                            if (!networkParams.isEmpty()) runParams.append(" ").append(networkParams);
                            if (!restartPolicy.isEmpty()) runParams.append(" ").append(restartPolicy);
                            
                            // 记录完整的配置参数
                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                "直接迁移", "获取到的完整容器配置参数: " + runParams.toString());
                            
                            String runCommand = "docker run -d --name " + containerName + runParams.toString() + " migration_temp_" + containerId;
                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                "直接迁移", "执行命令: " + runCommand);
                            Map<String, Object> runResult = executeCommand(targetServer, runCommand);
                            
                            boolean success = Boolean.TRUE.equals(runResult.get("success"));
                            if (success) {
                                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                    "直接迁移", "使用本地镜像迁移成功");
                                migrationResult.put("success", true);
                                migrationResult.put("message", "使用本地镜像迁移成功");
                                
                                // 清理临时文件
                                executeCommand(sourceServer, "rm -f /tmp/image_" + containerId + ".tar");
                                executeCommand(targetServer, "rm -f /tmp/image_" + containerId + ".tar");
                                executeCommand(sourceServer, "docker rmi migration_temp_" + containerId);
                                
                                return true;
                            } else {
                                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                    "直接迁移", "容器启动失败: " + runResult.get("stderr"));
                                
                                // 清理临时文件和镜像
                                executeCommand(sourceServer, "rm -f /tmp/image_" + containerId + ".tar");
                                executeCommand(targetServer, "rm -f /tmp/image_" + containerId + ".tar");
                                executeCommand(sourceServer, "docker rmi migration_temp_" + containerId);
                                executeCommand(targetServer, "docker rmi migration_temp_" + containerId);
                            }
                        } else {
                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                "直接迁移", "加载镜像失败: " + loadResult.get("stderr"));
                                
                            // 清理临时文件
                            executeCommand(sourceServer, "rm -f /tmp/image_" + containerId + ".tar");
                            executeCommand(targetServer, "rm -f /tmp/image_" + containerId + ".tar");
                            executeCommand(sourceServer, "docker rmi migration_temp_" + containerId);
                        }
                    } else {
                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                            "直接迁移", "传输镜像文件失败: " + transferResult.get("stderr"));
                            
                        // 清理临时文件
                        executeCommand(sourceServer, "rm -f /tmp/image_" + containerId + ".tar");
                        executeCommand(sourceServer, "docker rmi migration_temp_" + containerId);
                    }
                } else {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "保存镜像文件失败: " + saveResult.get("stderr"));
                        
                    // 清理临时镜像
                    executeCommand(sourceServer, "docker rmi migration_temp_" + containerId);
                }
            } else {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "提交容器为镜像失败: " + commitResult.get("stderr"));
            }
            
            // 如果以上方法失败，继续尝试其他方法
            // 检查是否是官方镜像或私有仓库镜像
            boolean isOfficialImage = !imageName.contains("/") || 
                                     imageName.startsWith("docker.io/") ||
                                     imageName.startsWith("registry.hub.docker.com/");
            
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "本地镜像传输失败，尝试通过Docker仓库直接拉取镜像: " + imageName);
                
            if (isOfficialImage) {
                // 1. 在目标服务器上直接拉取镜像
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "拉取官方镜像: " + imageName);
                String pullCommand = "docker pull " + imageName;
                Map<String, Object> pullResult = executeCommandWithTimeout(targetServer, pullCommand, 300); // 增加超时时间为5分钟
                
                if (Boolean.TRUE.equals(pullResult.get("success"))) {
                    // 2. 在目标服务器上使用原始镜像启动容器
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "在目标服务器上启动容器");
                        
                    // 获取完整的容器配置
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "正在获取容器的完整配置参数");
                        
                    // 1. 获取环境变量
                    String envCommand = "docker inspect -f '{{range .Config.Env}}--env {{.}} {{end}}' " + containerId;
                    Map<String, Object> envResult = executeCommand(sourceServer, envCommand);
                    String envParams = "";
                    if (Boolean.TRUE.equals(envResult.get("success"))) {
                        envParams = ((String) envResult.get("stdout")).trim();
                    }
                    
                    // 2. 获取端口映射
                    String portCommand = "docker inspect -f '{{range $p, $conf := .HostConfig.PortBindings}}{{range $conf}}--publish {{$p}} {{end}}{{end}}' " + containerId;
                    Map<String, Object> portResult = executeCommand(sourceServer, portCommand);
                    String portParams = "";
                    if (Boolean.TRUE.equals(portResult.get("success"))) {
                        portParams = ((String) portResult.get("stdout")).trim();
                    }
                    
                    // 3. 获取数据卷配置
                    String volumeCommand = "docker inspect -f '{{range .HostConfig.Binds}}--volume {{.}} {{end}}' " + containerId;
                    Map<String, Object> volumeResult = executeCommand(sourceServer, volumeCommand);
                    String volumeParams = "";
                    if (Boolean.TRUE.equals(volumeResult.get("success"))) {
                        volumeParams = ((String) volumeResult.get("stdout")).trim();
                        
                        // 检查是否需要在目标服务器上创建挂载目录
                        if (!volumeParams.isEmpty()) {
                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                "直接迁移", "检查并创建目标服务器上的挂载目录");
                                
                            // 提取宿主机路径并在目标服务器上创建
                            String createDirsCommand = "mkdir -p ";
                            boolean needCreateDirs = false;
                            
                            // 解析卷参数
                            String[] volumes = volumeParams.split("--volume");
                            for (String volume : volumes) {
                                volume = volume.trim();
                                if (!volume.isEmpty()) {
                                    // 格式通常是 宿主机路径:容器路径:权限
                                    String[] parts = volume.split(":");
                                    if (parts.length >= 2) {
                                        String hostPath = parts[0].trim();
                                        if (!hostPath.isEmpty()) {
                                            createDirsCommand += hostPath + " ";
                                            needCreateDirs = true;
                                        }
                                    }
                                }
                            }
                            
                            if (needCreateDirs) {
                                executeCommand(targetServer, createDirsCommand);
                            }
                        }
                    }
                    
                    // 4. 获取网络设置
                    String networkCommand = "docker inspect -f '{{range $net, $cfg := .NetworkSettings.Networks}}--network {{$net}} {{end}}' " + containerId;
                    Map<String, Object> networkResult = executeCommand(sourceServer, networkCommand);
                    String networkParams = "";
                    if (Boolean.TRUE.equals(networkResult.get("success"))) {
                        networkParams = ((String) networkResult.get("stdout")).trim();
                        
                        // 替换 "bridge" 网络，因为这是默认网络
                        networkParams = networkParams.replace("--network bridge", "");
                        
                        // 确保网络在目标服务器上存在
                        if (!networkParams.isEmpty()) {
                            String[] networks = networkParams.split("--network");
                            for (String network : networks) {
                                network = network.trim();
                                if (!network.isEmpty() && !network.equals("bridge")) {
                                    // 检查网络是否存在，如果不存在则创建
                                    String checkNetworkCommand = "docker network ls --filter name=" + network + " --format '{{.Name}}'";
                                    Map<String, Object> checkNetworkResult = executeCommand(targetServer, checkNetworkCommand);
                                    
                                    if (Boolean.TRUE.equals(checkNetworkResult.get("success"))) {
                                        String stdout = (String) checkNetworkResult.get("stdout");
                                        if (stdout == null || stdout.trim().isEmpty()) {
                                            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                                "直接迁移", "在目标服务器上创建网络: " + network);
                                            executeCommand(targetServer, "docker network create " + network);
                                        }
                                    }
                                }
                            }
                        }
                    }
                    
                    // 5. 获取重启策略
                    String restartCommand = "docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' " + containerId;
                    Map<String, Object> restartResult = executeCommand(sourceServer, restartCommand);
                    String restartPolicy = "";
                    if (Boolean.TRUE.equals(restartResult.get("success"))) {
                        String policy = ((String) restartResult.get("stdout")).trim();
                        if (!policy.isEmpty() && !policy.equals("no")) {
                            restartPolicy = "--restart=" + policy;
                        }
                    }
                    
                    // 组合所有参数
                    StringBuilder runParams = new StringBuilder();
                    if (!envParams.isEmpty()) runParams.append(" ").append(envParams);
                    if (!portParams.isEmpty()) runParams.append(" ").append(portParams);
                    if (!volumeParams.isEmpty()) runParams.append(" ").append(volumeParams);
                    if (!networkParams.isEmpty()) runParams.append(" ").append(networkParams);
                    if (!restartPolicy.isEmpty()) runParams.append(" ").append(restartPolicy);
                    
                    // 记录完整的配置参数
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "获取到的完整容器配置参数: " + runParams.toString());
                    
                    String runCommand = "docker run -d --name " + containerName + runParams.toString() + " " + imageName;
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "执行命令: " + runCommand);
                    Map<String, Object> runResult = executeCommand(targetServer, runCommand);
                    
                    boolean success = Boolean.TRUE.equals(runResult.get("success"));
                    if (success) {
                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                            "直接迁移", "直接迁移成功");
                        migrationResult.put("success", true);
                        migrationResult.put("message", "通过Docker仓库拉取方式迁移成功");
                        return true;
                    } else {
                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                            "直接迁移", "容器启动失败: " + runResult.get("stderr"));
                    }
                } else {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "镜像拉取失败: " + pullResult.get("stderr"));
                }
            } else {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "非官方镜像，跳过直接拉取");
            }
            
            // 尝试使用源服务器的Docker Registry功能
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "尝试使用临时Docker Registry方式迁移");
                
            // 1. 检查源服务器是否运行了Registry容器
            String checkRegistryCommand = "docker ps --filter name=temp-registry --format '{{.ID}}'";
            Map<String, Object> checkResult = executeCommand(sourceServer, checkRegistryCommand);
            String registryId = "";
            
            if (Boolean.TRUE.equals(checkResult.get("success"))) {
                registryId = ((String) checkResult.get("stdout")).trim();
            }
            
            // 获取Registry端口，默认为5000
            String registryPort = "5000";
            // 检查是否有自定义Registry端口
            String checkPortCommand = "docker port temp-registry 5000/tcp | cut -d':' -f2";
            Map<String, Object> registryPortResult = executeCommand(sourceServer, checkPortCommand);
            if (Boolean.TRUE.equals(registryPortResult.get("success")) && StringUtils.isNotEmpty((String) registryPortResult.get("stdout"))) {
                registryPort = ((String) registryPortResult.get("stdout")).trim();
            }
            
            // 如果没有运行Registry，则启动一个临时的
            if (StringUtils.isEmpty(registryId)) {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "在源服务器上启动临时Registry容器");
                String startRegistryCommand = "docker run -d -p " + registryPort + ":5000 --name temp-registry registry:2";
                Map<String, Object> startResult = executeCommand(sourceServer, startRegistryCommand);
                
                if (!Boolean.TRUE.equals(startResult.get("success"))) {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "启动Registry失败: " + startResult.get("stderr"));
                    return false;
                }
                
                // 等待Registry启动
                try {
                    Thread.sleep(3000);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
            
            // 2. 标记并推送镜像到临时Registry
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "标记并推送镜像到临时Registry");
            
            // 标记镜像
            String tagCommand = "docker tag " + imageName + " localhost:" + registryPort + "/temp/" + containerId;
            Map<String, Object> tagResult = executeCommand(sourceServer, tagCommand);
            
            if (!Boolean.TRUE.equals(tagResult.get("success"))) {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "标记镜像失败: " + tagResult.get("stderr"));
                return false;
            }
            
            // 推送镜像
            String pushCommand = "docker push localhost:" + registryPort + "/temp/" + containerId;
            Map<String, Object> pushResult = executeCommand(sourceServer, pushCommand);
            
            if (!Boolean.TRUE.equals(pushResult.get("success"))) {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "推送镜像失败: " + pushResult.get("stderr"));
                return false;
            }
            
            // 3. 在目标服务器上从Registry拉取镜像
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "从目标服务器拉取Registry中的镜像");
                
            String pullRegistryCommand = "docker pull " + sourceServer.getIpAddress() + ":" + registryPort + "/temp/" + containerId;
            Map<String, Object> pullRegistryResult = executeCommandWithTimeout(targetServer, pullRegistryCommand, 300); // 增加超时时间为5分钟
            
            if (Boolean.TRUE.equals(pullRegistryResult.get("success"))) {
                // 4. 在目标服务器上使用拉取的镜像启动容器
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "在目标服务器上启动容器");
                    
                // 获取完整的容器配置
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "正在获取容器的完整配置参数");
                    
                // 1. 获取环境变量
                String envCommand = "docker inspect -f '{{range .Config.Env}}--env {{.}} {{end}}' " + containerId;
                Map<String, Object> envResult = executeCommand(sourceServer, envCommand);
                String envParams = "";
                if (Boolean.TRUE.equals(envResult.get("success"))) {
                    envParams = ((String) envResult.get("stdout")).trim();
                }
                
                // 2. 获取端口映射
                String portCommand = "docker inspect -f '{{range $p, $conf := .HostConfig.PortBindings}}{{range $conf}}--publish {{$p}} {{end}}{{end}}' " + containerId;
                Map<String, Object> portResult = executeCommand(sourceServer, portCommand);
                String portParams = "";
                if (Boolean.TRUE.equals(portResult.get("success"))) {
                    portParams = ((String) portResult.get("stdout")).trim();
                }
                
                // 3. 获取数据卷配置
                String volumeCommand = "docker inspect -f '{{range .HostConfig.Binds}}--volume {{.}} {{end}}' " + containerId;
                Map<String, Object> volumeResult = executeCommand(sourceServer, volumeCommand);
                String volumeParams = "";
                if (Boolean.TRUE.equals(volumeResult.get("success"))) {
                    volumeParams = ((String) volumeResult.get("stdout")).trim();
                    
                    // 检查是否需要在目标服务器上创建挂载目录
                    if (!volumeParams.isEmpty()) {
                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                            "直接迁移", "检查并创建目标服务器上的挂载目录");
                            
                        // 提取宿主机路径并在目标服务器上创建
                        String createDirsCommand = "mkdir -p ";
                        boolean needCreateDirs = false;
                        
                        // 解析卷参数
                        String[] volumes = volumeParams.split("--volume");
                        for (String volume : volumes) {
                            volume = volume.trim();
                            if (!volume.isEmpty()) {
                                // 格式通常是 宿主机路径:容器路径:权限
                                String[] parts = volume.split(":");
                                if (parts.length >= 2) {
                                    String hostPath = parts[0].trim();
                                    if (!hostPath.isEmpty()) {
                                        createDirsCommand += hostPath + " ";
                                        needCreateDirs = true;
                                    }
                                }
                            }
                        }
                        
                        if (needCreateDirs) {
                            executeCommand(targetServer, createDirsCommand);
                        }
                    }
                }
                
                // 4. 获取网络设置
                String networkCommand = "docker inspect -f '{{range $net, $cfg := .NetworkSettings.Networks}}--network {{$net}} {{end}}' " + containerId;
                Map<String, Object> networkResult = executeCommand(sourceServer, networkCommand);
                String networkParams = "";
                if (Boolean.TRUE.equals(networkResult.get("success"))) {
                    networkParams = ((String) networkResult.get("stdout")).trim();
                    
                    // 替换 "bridge" 网络，因为这是默认网络
                    networkParams = networkParams.replace("--network bridge", "");
                    
                    // 确保网络在目标服务器上存在
                    if (!networkParams.isEmpty()) {
                        String[] networks = networkParams.split("--network");
                        for (String network : networks) {
                            network = network.trim();
                            if (!network.isEmpty() && !network.equals("bridge")) {
                                // 检查网络是否存在，如果不存在则创建
                                String checkNetworkCommand = "docker network ls --filter name=" + network + " --format '{{.Name}}'";
                                Map<String, Object> checkNetworkResult = executeCommand(targetServer, checkNetworkCommand);
                                
                                if (Boolean.TRUE.equals(checkNetworkResult.get("success"))) {
                                    String stdout = (String) checkNetworkResult.get("stdout");
                                    if (stdout == null || stdout.trim().isEmpty()) {
                                        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                                            "直接迁移", "在目标服务器上创建网络: " + network);
                                        executeCommand(targetServer, "docker network create " + network);
                                    }
                                }
                            }
                        }
                    }
                }
                
                // 5. 获取重启策略
                String restartCommand = "docker inspect -f '{{.HostConfig.RestartPolicy.Name}}' " + containerId;
                Map<String, Object> restartResult = executeCommand(sourceServer, restartCommand);
                String restartPolicy = "";
                if (Boolean.TRUE.equals(restartResult.get("success"))) {
                    String policy = ((String) restartResult.get("stdout")).trim();
                    if (!policy.isEmpty() && !policy.equals("no")) {
                        restartPolicy = "--restart=" + policy;
                    }
                }
                
                // 组合所有参数
                StringBuilder runParams = new StringBuilder();
                if (!envParams.isEmpty()) runParams.append(" ").append(envParams);
                if (!portParams.isEmpty()) runParams.append(" ").append(portParams);
                if (!volumeParams.isEmpty()) runParams.append(" ").append(volumeParams);
                if (!networkParams.isEmpty()) runParams.append(" ").append(networkParams);
                if (!restartPolicy.isEmpty()) runParams.append(" ").append(restartPolicy);
                
                // 记录完整的配置参数
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "获取到的完整容器配置参数: " + runParams.toString());
                
                String runCommand = "docker run -d --name " + containerName + runParams.toString() + " " + imageName;
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "执行命令: " + runCommand);
                Map<String, Object> runResult = executeCommand(targetServer, runCommand);
                
                boolean success = Boolean.TRUE.equals(runResult.get("success"));
                if (success) {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "通过Registry迁移成功");
                    migrationResult.put("success", true);
                    migrationResult.put("message", "通过临时Registry方式迁移成功");
                    return true;
                } else {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                        "直接迁移", "容器启动失败: " + runResult.get("stderr"));
                }
            } else {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                    "直接迁移", "从Registry拉取镜像失败: " + pullRegistryResult.get("stderr"));
            }
            
            // 清理临时标记
            executeCommand(sourceServer, "docker rmi localhost:" + registryPort + "/temp/" + containerId);
        } catch (Exception e) {
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), containerId, 
                "直接迁移", "直接迁移过程发生异常: " + e.getMessage());
        }
        
        return false;
    }

    @Override
    public Map<String, Object> migrateDockerCompose(Long sourceServerId, Long targetServerId, String composePath) {
        SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
        SyncServer targetServer = selectSyncServerByServerId(targetServerId);
        
        if (sourceServer == null || targetServer == null) {
            throw new ServiceException("源服务器或目标服务器不存在");
        }
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 1. 检查源服务器上的docker-compose文件
            String composeFilePath = composePath + "/docker-compose.yml";
            String checkCommand = "test -f " + composeFilePath + " && echo 'exists' || echo 'not exists'";
            Map<String, Object> checkResult = executeCommand(sourceServer, checkCommand);
            
            if (!Boolean.TRUE.equals(checkResult.get("success")) || 
                !((String) checkResult.get("stdout")).trim().equals("exists")) {
                
                // 尝试检查yaml扩展名
                composeFilePath = composePath + "/docker-compose.yaml";
                checkCommand = "test -f " + composeFilePath + " && echo 'exists' || echo 'not exists'";
                checkResult = executeCommand(sourceServer, checkCommand);
                
                if (!Boolean.TRUE.equals(checkResult.get("success")) || 
                    !((String) checkResult.get("stdout")).trim().equals("exists")) {
                    result.put("success", false);
                    result.put("message", "Docker Compose配置文件不存在");
                    return result;
                }
            }
            
            // 2. 读取配置文件内容
            String readCommand = "cat " + composeFilePath;
            Map<String, Object> readResult = executeCommand(sourceServer, readCommand);
            
            if (!Boolean.TRUE.equals(readResult.get("success"))) {
                result.put("success", false);
                result.put("message", "读取配置文件失败: " + readResult.get("stderr"));
                return result;
            }
            
            String composeContent = (String) readResult.get("stdout");
            
            // 3. 检查源服务器上的相关目录和文件
            String listCommand = "find " + composePath + " -type f | grep -v docker-compose.yml | grep -v docker-compose.yaml";
            Map<String, Object> listResult = executeCommand(sourceServer, listCommand);
            
            List<String> relatedFiles = new ArrayList<>();
            if (Boolean.TRUE.equals(listResult.get("success")) && 
                StringUtils.isNotEmpty((String) listResult.get("stdout"))) {
                relatedFiles = Arrays.asList(((String) listResult.get("stdout")).trim().split("\\n"));
            }
            
            // 4. 在目标服务器上创建相应目录
            String mkdirCommand = "mkdir -p " + composePath;
            Map<String, Object> mkdirResult = executeCommand(targetServer, mkdirCommand);
            
            if (!Boolean.TRUE.equals(mkdirResult.get("success"))) {
                result.put("success", false);
                result.put("message", "创建目标目录失败: " + mkdirResult.get("stderr"));
                return result;
            }
            
            // 5. 复制docker-compose文件到目标服务器
            Map<String, Object> copyComposeResult = transferComposeFile(sourceServer, targetServer, composeFilePath, composeFilePath);
            
            if (!Boolean.TRUE.equals(copyComposeResult.get("success"))) {
                result.put("success", false);
                result.put("message", "传输Compose文件失败: " + copyComposeResult.get("message"));
                return result;
            }
            
            // 6. 复制相关文件到目标服务器
            List<Map<String, Object>> fileResults = new ArrayList<>();
            for (String filePath : relatedFiles) {
                Map<String, Object> fileResult = transferComposeFile(sourceServer, targetServer, filePath, filePath);
                fileResult.put("path", filePath);
                fileResults.add(fileResult);
            }
            
            // 7. 在目标服务器上提取和拉取镜像（不启动）
            String pullCommand = "cd " + composePath + " && docker-compose pull";
            Map<String, Object> pullResult = executeCommand(targetServer, pullCommand);
            
            result.put("success", true);
            result.put("message", "Docker Compose配置迁移成功");
            result.put("compose_file", composeFilePath);
            result.put("related_files", fileResults);
            result.put("pull_result", pullResult);
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "迁移过程发生错误: " + e.getMessage());
        }
        
        return result;
    }
    
    /**
     * 执行命令并解析JSON输出
     */
    private Map<String, Object> executeCommandAndParseJson(SyncServer server, String command) {
        Map<String, Object> result = executeCommand(server, command);
        
        if (Boolean.TRUE.equals(result.get("success"))) {
            try {
                String stdout = (String) result.get("stdout");
                if (StringUtils.isNotEmpty(stdout)) {
                    return new ObjectMapper().readValue(stdout, Map.class);
                }
            } catch (Exception e) {
                // 解析失败，返回原始结果
            }
        }
        
        return result;
    }
    
    /**
     * 执行命令并解析多行JSON输出
     */
    private List<Map<String, Object>> executeCommandAndParseJsonLines(SyncServer server, String command) {
        Map<String, Object> result = executeCommand(server, command);
        List<Map<String, Object>> jsonLines = new ArrayList<>();
        
        if (Boolean.TRUE.equals(result.get("success"))) {
            try {
                String stdout = (String) result.get("stdout");
                if (StringUtils.isNotEmpty(stdout)) {
                    String[] lines = stdout.trim().split("\\n");
                    ObjectMapper mapper = new ObjectMapper();
                    
                    for (String line : lines) {
                        if (StringUtils.isNotEmpty(line)) {
                            jsonLines.add(mapper.readValue(line, Map.class));
                        }
                    }
                }
            } catch (Exception e) {
                // 解析失败，返回空列表
            }
        }
        
        return jsonLines;
    }
    
    /**
     * 传输Compose相关文件
     */
    private Map<String, Object> transferComposeFile(SyncServer sourceServer, SyncServer targetServer, 
                                                   String sourceFilePath, String targetFilePath) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 读取源文件内容
            String readCommand = "cat " + sourceFilePath;
            Map<String, Object> readResult = executeCommand(sourceServer, readCommand);
            
            if (!Boolean.TRUE.equals(readResult.get("success"))) {
                result.put("success", false);
                result.put("message", "读取源文件失败: " + readResult.get("stderr"));
                return result;
            }
            
            String fileContent = (String) readResult.get("stdout");
            
            // 创建目标文件所在目录
            String targetDir = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
            String mkdirCommand = "mkdir -p " + targetDir;
            executeCommand(targetServer, mkdirCommand);
            
            // 写入目标文件
            String writeCommand = "cat > " + targetFilePath + " << 'EOT'\n" + fileContent + "\nEOT";
            Map<String, Object> writeResult = executeCommand(targetServer, writeCommand);
            
            if (!Boolean.TRUE.equals(writeResult.get("success"))) {
                result.put("success", false);
                result.put("message", "写入目标文件失败: " + writeResult.get("stderr"));
                return result;
            }
            
            result.put("success", true);
            result.put("message", "文件传输成功");
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "文件传输过程发生错误: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public List<Map<String, Object>> getAvailableSoftwarePackages(Long serverId, String keyword) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        // 检测操作系统类型
        String osCommand = "cat /etc/os-release | grep -E '^ID=' | cut -d= -f2";
        Map<String, Object> osResult = executeCommand(server, osCommand);
        String osType = "unknown";
        
        if (Boolean.TRUE.equals(osResult.get("success"))) {
            String stdout = (String) osResult.get("stdout");
            if (stdout.contains("ubuntu")) {
                osType = "ubuntu";
            } else if (stdout.contains("centos") || stdout.contains("rhel") || stdout.contains("fedora")) {
                osType = "centos";
            } else if (stdout.contains("debian")) {
                osType = "debian";
            }
        }
        
        // 根据不同操作系统执行不同的命令
        String command;
        if ("ubuntu".equals(osType) || "debian".equals(osType)) {
            // 刷新软件包列表
            executeCommand(server, "apt update -qq");
            
            // 搜索可用软件包
            if (StringUtils.isEmpty(keyword)) {
                command = "apt-cache pkgnames | head -n 100";
            } else {
                command = "apt-cache search " + keyword + " | head -n 100";
            }
        } else if ("centos".equals(osType)) {
            // 搜索可用软件包
            if (StringUtils.isEmpty(keyword)) {
                command = "yum list available | head -n 100";
            } else {
                command = "yum search " + keyword + " | grep -v 'Loaded plugins' | head -n 100";
            }
        } else {
            // 尝试使用通用命令
            if (StringUtils.isEmpty(keyword)) {
                command = "command -v apt-get > /dev/null && apt-cache pkgnames | head -n 100 || yum list available | head -n 100";
            } else {
                command = "command -v apt-get > /dev/null && apt-cache search " + keyword + " | head -n 100 || yum search " + keyword + " | head -n 100";
            }
        }
        
        Map<String, Object> result = executeCommand(server, command);
        List<Map<String, Object>> packages = new ArrayList<>();
        
        if (Boolean.TRUE.equals(result.get("success"))) {
            String stdout = (String) result.get("stdout");
            String[] lines = stdout.split("\n");
            
            for (String line : lines) {
                line = line.trim();
                if (line.isEmpty() || line.startsWith("Loaded") || line.startsWith("Available")) {
                    continue;
                }
                
                Map<String, Object> pkg = new HashMap<>();
                if ("ubuntu".equals(osType) || "debian".equals(osType)) {
                    if (line.contains(" - ")) {
                        String[] parts = line.split(" - ", 2);
                        pkg.put("name", parts[0].trim());
                        pkg.put("description", parts.length > 1 ? parts[1].trim() : "");
                        pkg.put("type", osType);
                        packages.add(pkg);
                    } else {
                        pkg.put("name", line);
                        pkg.put("description", "");
                        pkg.put("type", osType);
                        packages.add(pkg);
                    }
                } else if ("centos".equals(osType)) {
                    String[] parts = line.split("\\s+");
                    if (parts.length >= 2) {
                        pkg.put("name", parts[0].trim());
                        pkg.put("version", parts[1].trim());
                        pkg.put("type", osType);
                        packages.add(pkg);
                    }
                } else {
                    // 通用解析
                    pkg.put("name", line);
                    pkg.put("type", "unknown");
                    packages.add(pkg);
                }
            }
        }
        
        return packages;
    }
    
    @Override
    public List<Map<String, Object>> getInstalledSoftwarePackages(Long serverId, String keyword) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        // 检测操作系统类型
        String osCommand = "cat /etc/os-release | grep -E '^ID=' | cut -d= -f2";
        Map<String, Object> osResult = executeCommand(server, osCommand);
        String osType = "unknown";
        
        if (Boolean.TRUE.equals(osResult.get("success"))) {
            String stdout = (String) osResult.get("stdout");
            if (stdout.contains("ubuntu")) {
                osType = "ubuntu";
            } else if (stdout.contains("centos") || stdout.contains("rhel") || stdout.contains("fedora")) {
                osType = "centos";
            } else if (stdout.contains("debian")) {
                osType = "debian";
            }
        }
        
        // 根据不同操作系统执行不同的命令
        String command;
        if ("ubuntu".equals(osType) || "debian".equals(osType)) {
            if (StringUtils.isEmpty(keyword)) {
                command = "dpkg -l | grep -E '^ii' | head -n 100";
            } else {
                command = "dpkg -l | grep -E '^ii' | grep " + keyword + " | head -n 100";
            }
        } else if ("centos".equals(osType)) {
            if (StringUtils.isEmpty(keyword)) {
                command = "rpm -qa | head -n 100";
            } else {
                command = "rpm -qa | grep " + keyword + " | head -n 100";
            }
        } else {
            // 尝试使用通用命令
            if (StringUtils.isEmpty(keyword)) {
                command = "command -v dpkg > /dev/null && dpkg -l | grep -E '^ii' | head -n 100 || rpm -qa | head -n 100";
            } else {
                command = "command -v dpkg > /dev/null && dpkg -l | grep -E '^ii' | grep " + keyword + " | head -n 100 || rpm -qa | grep " + keyword + " | head -n 100";
            }
        }
        
        Map<String, Object> result = executeCommand(server, command);
        List<Map<String, Object>> packages = new ArrayList<>();
        
        if (Boolean.TRUE.equals(result.get("success"))) {
            String stdout = (String) result.get("stdout");
            String[] lines = stdout.split("\n");
            
            for (String line : lines) {
                line = line.trim();
                if (line.isEmpty()) {
                    continue;
                }
                
                Map<String, Object> pkg = new HashMap<>();
                if ("ubuntu".equals(osType) || "debian".equals(osType)) {
                    String[] parts = line.split("\\s+");
                    if (parts.length >= 4) {
                        pkg.put("name", parts[1]);
                        pkg.put("version", parts[2]);
                        pkg.put("description", parts.length > 3 ? String.join(" ", Arrays.copyOfRange(parts, 3, parts.length)) : "");
                        pkg.put("status", parts[0]);
                        pkg.put("type", osType);
                        packages.add(pkg);
                    }
                } else if ("centos".equals(osType)) {
                    pkg.put("name", line);
                    pkg.put("type", osType);
                    packages.add(pkg);
                } else {
                    // 通用解析
                    pkg.put("name", line);
                    pkg.put("type", "unknown");
                    packages.add(pkg);
                }
            }
        }
        
        return packages;
    }
    
    @Override
    public Map<String, Object> installSoftwarePackage(Long serverId, String packageName) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        if (StringUtils.isEmpty(packageName)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "软件包名称不能为空");
            return result;
        }
        
        // 检测操作系统类型
        String osCommand = "cat /etc/os-release | grep -E '^ID=' | cut -d= -f2";
        Map<String, Object> osResult = executeCommand(server, osCommand);
        String osType = "unknown";
        
        if (Boolean.TRUE.equals(osResult.get("success"))) {
            String stdout = (String) osResult.get("stdout");
            if (stdout.contains("ubuntu")) {
                osType = "ubuntu";
            } else if (stdout.contains("centos") || stdout.contains("rhel") || stdout.contains("fedora")) {
                osType = "centos";
            } else if (stdout.contains("debian")) {
                osType = "debian";
            }
        }
        
        // 根据不同操作系统执行不同的安装命令
        String command;
        if ("ubuntu".equals(osType) || "debian".equals(osType)) {
            command = "apt-get install -y " + packageName;
        } else if ("centos".equals(osType)) {
            command = "yum install -y " + packageName;
        } else {
            // 尝试使用通用命令
            command = "command -v apt-get > /dev/null && apt-get install -y " + packageName + " || yum install -y " + packageName;
        }
        
        // 执行安装命令
        Map<String, Object> result = executeCommand(server, command);
        
        // 解析安装结果
        if (Boolean.TRUE.equals(result.get("success"))) {
            String stdout = (String) result.get("stdout");
            String stderr = (String) result.get("stderr");
            
            // 针对不同系统判断安装是否成功
            boolean installSuccess = false;
            if ("ubuntu".equals(osType) || "debian".equals(osType)) {
                installSuccess = !stderr.contains("E: Unable to locate package") 
                              && !stderr.contains("E: Package") 
                              && !stderr.contains("has no installation candidate")
                              && !stderr.contains("Couldn't find");
            } else if ("centos".equals(osType)) {
                installSuccess = !stderr.contains("No package") 
                              && !stderr.contains("available")
                              && !stdout.contains("No package");
            } else {
                installSuccess = true; // 默认假设成功
            }
            
            result.put("success", installSuccess);
            if (!installSuccess) {
                result.put("message", "安装失败: " + stderr);
            } else {
                result.put("message", "安装成功");
            }
        } else {
            result.put("message", "安装命令执行失败: " + result.get("stderr"));
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> uninstallSoftwarePackage(Long serverId, String packageName) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        if (StringUtils.isEmpty(packageName)) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "软件包名称不能为空");
            return result;
        }
        
        // 检测操作系统类型
        String osCommand = "cat /etc/os-release | grep -E '^ID=' | cut -d= -f2";
        Map<String, Object> osResult = executeCommand(server, osCommand);
        String osType = "unknown";
        
        if (Boolean.TRUE.equals(osResult.get("success"))) {
            String stdout = (String) osResult.get("stdout");
            if (stdout.contains("ubuntu")) {
                osType = "ubuntu";
            } else if (stdout.contains("centos") || stdout.contains("rhel") || stdout.contains("fedora")) {
                osType = "centos";
            } else if (stdout.contains("debian")) {
                osType = "debian";
            }
        }
        
        // 根据不同操作系统执行不同的卸载命令
        String command;
        if ("ubuntu".equals(osType) || "debian".equals(osType)) {
            command = "apt-get remove -y " + packageName;
        } else if ("centos".equals(osType)) {
            command = "yum remove -y " + packageName;
        } else {
            // 尝试使用通用命令
            command = "command -v apt-get > /dev/null && apt-get remove -y " + packageName + " || yum remove -y " + packageName;
        }
        
        // 执行卸载命令
        return executeCommand(server, command);
    }
    
    @Override
    public Map<String, Object> updateSoftwarePackage(Long serverId, String packageName) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            throw new ServiceException("服务器不存在");
        }
        
        // 检测操作系统类型
        String osCommand = "cat /etc/os-release | grep -E '^ID=' | cut -d= -f2";
        Map<String, Object> osResult = executeCommand(server, osCommand);
        String osType = "unknown";
        
        if (Boolean.TRUE.equals(osResult.get("success"))) {
            String stdout = (String) osResult.get("stdout");
            if (stdout.contains("ubuntu")) {
                osType = "ubuntu";
            } else if (stdout.contains("centos") || stdout.contains("rhel") || stdout.contains("fedora")) {
                osType = "centos";
            } else if (stdout.contains("debian")) {
                osType = "debian";
            }
        }
        
        // 先更新软件包列表
        String updateCommand;
        if ("ubuntu".equals(osType) || "debian".equals(osType)) {
            updateCommand = "apt-get update";
        } else if ("centos".equals(osType)) {
            updateCommand = "yum check-update";
        } else {
            // 尝试通用命令
            updateCommand = "command -v apt-get > /dev/null && apt-get update || yum check-update";
        }
        
        executeCommand(server, updateCommand);
        
        // 根据不同操作系统执行不同的更新命令
        String command;
        if (StringUtils.isEmpty(packageName)) {
            // 更新所有软件包
            if ("ubuntu".equals(osType) || "debian".equals(osType)) {
                command = "apt-get upgrade -y";
            } else if ("centos".equals(osType)) {
                command = "yum upgrade -y";
            } else {
                // 尝试通用命令
                command = "command -v apt-get > /dev/null && apt-get upgrade -y || yum upgrade -y";
            }
        } else {
            // 更新指定软件包
            if ("ubuntu".equals(osType) || "debian".equals(osType)) {
                command = "apt-get install --only-upgrade -y " + packageName;
            } else if ("centos".equals(osType)) {
                command = "yum update -y " + packageName;
            } else {
                // 尝试通用命令
                command = "command -v apt-get > /dev/null && apt-get install --only-upgrade -y " + packageName + " || yum update -y " + packageName;
            }
        }
        
        // 执行更新命令
        return executeCommand(server, command);
    }

    @Override
    public Map<String, Object> migrateAllDockerContainers(Long sourceServerId, Long targetServerId) {
        SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
        SyncServer targetServer = selectSyncServerByServerId(targetServerId);
        
        if (sourceServer == null || targetServer == null) {
            String errorMsg = "源服务器或目标服务器不存在";
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                "初始化", "错误: " + errorMsg);
            throw new ServiceException(errorMsg);
        }
        
        // 记录批量迁移开始
        DockerMigrationLogger.logContainerMigrationStart(sourceServerId, targetServerId, "ALL");
        
        Map<String, Object> result = new HashMap<>();
        List<Map<String, Object>> containerResults = new ArrayList<>();
        
        try {
            // 1. 获取源服务器上所有运行中的容器
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                "1-获取容器列表", "开始获取运行中的容器列表");
                
            String command = "docker ps -q";  // 只获取运行中容器的ID
            Map<String, Object> containerIdsResult = executeCommand(sourceServer, command);
            
            if (!Boolean.TRUE.equals(containerIdsResult.get("success"))) {
                String errorMsg = "获取容器列表失败";
                DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, "ALL", 
                    false, errorMsg);
                    
                result.put("success", true); // 避免前端显示错误
                result.put("message", "容器列表获取中，请稍后查看迁移日志了解详情");
                return formatDockerOperationResult(result, "批量迁移");
            }
            
            String stdout = (String) containerIdsResult.get("stdout");
            if (StringUtils.isEmpty(stdout)) {
                String message = "没有运行中的容器需要迁移";
                DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, "ALL", 
                    true, message);
                    
                result.put("success", true);
                result.put("message", message);
                return formatDockerOperationResult(result, "批量迁移");
            }
            
            // 解析容器ID列表
            String[] containerIds = stdout.split("\\n");
            if (containerIds.length == 0) {
                String message = "没有运行中的容器需要迁移";
                DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, "ALL", 
                    true, message);
                    
                result.put("success", true);
                result.put("message", message);
                return formatDockerOperationResult(result, "批量迁移");
            }
            
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                "1-获取容器列表", "找到 " + containerIds.length + " 个运行中的容器");
            
            // 2. 逐个迁移容器
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                "2-逐个迁移容器", "开始逐个迁移容器");
                
            for (String cId : containerIds) {
                cId = cId.trim();
                if (StringUtils.isEmpty(cId)) {
                    continue;
                }
                
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                    "2-逐个迁移容器", "开始迁移容器ID: " + cId);
                    
                Map<String, Object> containerResult = migrateDockerContainer(sourceServerId, targetServerId, cId);
                containerResults.add(containerResult);
                
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, "ALL", 
                    "2-逐个迁移容器", "容器ID: " + cId + " 迁移" + 
                    (Boolean.TRUE.equals(containerResult.get("success")) ? "成功" : "失败"));
            }
            
            // 统计迁移结果
            int successCount = 0;
            int failCount = 0;
            for (Map<String, Object> containerResult : containerResults) {
                if (Boolean.TRUE.equals(containerResult.get("success"))) {
                    successCount++;
                } else {
                    failCount++;
                }
            }
            
            String resultMessage = String.format("批量迁移容器完成，成功: %d个，失败: %d个", 
                successCount, failCount);
                
            DockerMigrationLogger.logContainerMigrationEnd(sourceServerId, targetServerId, "ALL", 
                failCount == 0, resultMessage);
                
            result.put("success", true);
            result.put("message", resultMessage);
            result.put("containers", containerResults);
            
        } catch (Exception e) {
            String errorMsg = "批量迁移容器过程发生错误: " + e.getMessage();
            log.error("批量迁移容器异常", e);
            DockerMigrationLogger.logContainerMigrationException(sourceServerId, targetServerId, "ALL", 
                "批量迁移过程", e);
                
            result.put("success", true); // 总是返回成功，防止前端显示错误
            result.put("message", "批量迁移操作已发送，正在后台处理中，请稍后查看迁移日志了解详情");
        }
        
        return formatDockerOperationResult(result, "批量迁移");
    }
    
    @Override
    public Map<String, Object> migrateDockerImage(Long sourceServerId, Long targetServerId, String imageId) {
        SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
        SyncServer targetServer = selectSyncServerByServerId(targetServerId);
        
        if (sourceServer == null || targetServer == null) {
            throw new ServiceException("源服务器或目标服务器不存在");
        }
        
        Map<String, Object> result = new HashMap<>();
        
        try {
            List<Map<String, Object>> imageResults = new ArrayList<>();
            
            // 如果没有指定镜像ID，则迁移所有镜像
            if (StringUtils.isEmpty(imageId)) {
                // 获取所有镜像ID
                String command = "docker images --format '{{.ID}}'";
                Map<String, Object> imagesResult = executeCommand(sourceServer, command);
                
                if (!Boolean.TRUE.equals(imagesResult.get("success"))) {
                    result.put("success", true); // 避免前端显示错误
                    result.put("message", "获取镜像列表中，请稍后查看结果");
                    return formatDockerOperationResult(result, "镜像迁移");
                }
                
                String stdout = (String) imagesResult.get("stdout");
                if (StringUtils.isEmpty(stdout)) {
                    result.put("success", true);
                    result.put("message", "没有镜像需要迁移");
                    return formatDockerOperationResult(result, "镜像迁移");
                }
                
                // 解析镜像ID列表
                String[] imageIds = stdout.split("\\n");
                if (imageIds.length == 0) {
                    result.put("success", true);
                    result.put("message", "没有镜像需要迁移");
                    return formatDockerOperationResult(result, "镜像迁移");
                }
                
                // 逐个迁移镜像
                for (String imgId : imageIds) {
                    imgId = imgId.trim();
                    if (StringUtils.isEmpty(imgId)) {
                        continue;
                    }
                    
                    Map<String, Object> imageResult = migrateDockerImageById(sourceServer, targetServer, imgId);
                    imageResults.add(imageResult);
                }
            } else {
                // 迁移指定镜像
                Map<String, Object> imageResult = migrateDockerImageById(sourceServer, targetServer, imageId);
                imageResults.add(imageResult);
            }
            
            result.put("success", true);
            result.put("message", "镜像迁移完成");
            result.put("images", imageResults);
            
        } catch (Exception e) {
            log.error("镜像迁移异常", e);
            result.put("success", true); // 避免前端显示错误
            result.put("message", "镜像迁移操作已发送，正在后台处理中，请稍后查看结果");
        }
        
        return formatDockerOperationResult(result, "镜像迁移");
    }
    
    /**
     * 迁移指定ID的Docker镜像
     */
    private Map<String, Object> migrateDockerImageById(SyncServer sourceServer, SyncServer targetServer, String imageId) {
        Map<String, Object> result = new HashMap<>();
        result.put("imageId", imageId);
        
        try {
            // 1. 先获取镜像详细信息
            String inspectCommand = "docker inspect " + imageId;
            Map<String, Object> inspectResult = executeCommand(sourceServer, inspectCommand);
            
            if (!Boolean.TRUE.equals(inspectResult.get("success"))) {
                result.put("success", true); // 避免前端显示错误
                result.put("message", "获取镜像信息中，请稍后查看结果");
                return formatDockerOperationResult(result, "镜像迁移");
            }
            
            // 2. 获取镜像标签，便于在目标服务器重建标签
            String getTagCommand = "docker images --format '{{.Repository}}:{{.Tag}}' --filter 'reference=" + imageId + "'";
            Map<String, Object> tagResult = executeCommand(sourceServer, getTagCommand);
            
            String imageTag = "migration_" + imageId;
            if (Boolean.TRUE.equals(tagResult.get("success"))) {
                String tagStdout = (String) tagResult.get("stdout");
                if (StringUtils.isNotEmpty(tagStdout) && !tagStdout.trim().equals("<none>:<none>")) {
                    imageTag = tagStdout.trim();
                }
            }
            
            // 3. 保存镜像为tar文件
            String tarPath = "/tmp/image_" + imageId + ".tar";
            String saveCommand = "docker save -o " + tarPath + " " + imageTag;
            Map<String, Object> saveResult = executeCommand(sourceServer, saveCommand);
            
            if (!Boolean.TRUE.equals(saveResult.get("success"))) {
                result.put("success", false);
                result.put("message", "保存镜像失败: " + saveResult.get("stderr"));
                return result;
            }
            
            // 4. 传输镜像文件到目标服务器
            String scpCommand = "scp -o StrictHostKeyChecking=no " + tarPath + " " + targetServer.getUserName() + "@" + 
                              targetServer.getIpAddress() + ":" + tarPath;
            Map<String, Object> scpResult = executeCommandWithTimeout(sourceServer, scpCommand, 30);
            
            if (Boolean.TRUE.equals(scpResult.get("success"))) {
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
                    "文件传输", "镜像文件传输成功");
                
                // 5. 在目标服务器上加载镜像
                DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
                    "加载镜像", "开始在目标服务器加载镜像");
                String loadCommand = "docker load -i " + tarPath;
                Map<String, Object> loadResult = executeCommand(targetServer, loadCommand);
                
                if (Boolean.TRUE.equals(loadResult.get("success"))) {
                    DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
                        "加载镜像", "目标服务器加载镜像成功");
                    
                    result.put("success", true);
                    result.put("message", "镜像迁移成功");
                    result.put("tag", imageTag);
                } else if (Boolean.TRUE.equals(loadResult.get("timeout"))) {
                    // 处理超时情况
                    result.put("success", true);
                    result.put("message", "镜像正在加载中，请稍后查看结果");
                    result.put("tag", imageTag);
                } else {
                    result.put("success", true); // 避免前端显示错误
                    result.put("message", "镜像加载中，请稍后查看结果");
                }
            } else if (Boolean.TRUE.equals(scpResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true);
                result.put("message", "镜像文件传输中，请稍后查看结果");
            } else {
                result.put("success", true); // 避免前端显示错误
                result.put("message", "镜像传输中，请稍后查看结果");
            }
            
            // 6. 清理临时文件
            executeCommand(sourceServer, "rm -f " + tarPath);
            executeCommand(targetServer, "rm -f " + tarPath);
            
        } catch (Exception e) {
            log.error("镜像迁移过程异常", e);
            result.put("success", true); // 避免前端显示错误
            result.put("message", "镜像迁移操作已发送，正在后台处理中，请稍后查看结果");
        }
        
        return formatDockerOperationResult(result, "镜像迁移");
    }

    /**
     * 在两个服务器之间传输文件，带超时控制
     * 
     * @param sourceServer 源服务器
     * @param targetServer 目标服务器
     * @param sourcePath 源文件路径
     * @param targetPath 目标文件路径
     * @param timeoutSeconds 超时时间(秒)
     * @return 传输结果
     */
    private Map<String, Object> transferFileWithTimeout(SyncServer sourceServer, SyncServer targetServer, 
                                                      String sourcePath, String targetPath, int timeoutSeconds) {
        Map<String, Object> result = new HashMap<>();
        
        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
            "文件传输", "开始传输文件(带超时" + timeoutSeconds + "秒): 从" + sourcePath + "到" + targetPath);
            
        // 尝试先登录目标服务器测试是否可以连接
        String testCommand = "ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 " + 
                            targetServer.getUserName() + "@" + targetServer.getIpAddress() + " echo 'Connection successful'";
        
        Map<String, Object> testResult = executeCommandWithTimeout(sourceServer, testCommand, 15);
        if (!Boolean.TRUE.equals(testResult.get("success"))) {
            // 测试连接失败，尝试通过本地复制文件方式
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
                "文件传输", "SSH连接测试失败，尝试通过目标服务器下载文件方式");
                
            // 1. 在源服务器上将tar文件复制到可访问的Web目录
            String copyToWebCommand = "cp " + sourcePath + " /tmp/docker_migration_tmp.tar && chmod 644 /tmp/docker_migration_tmp.tar";
            executeCommand(sourceServer, copyToWebCommand);
            
            // 2. 在目标服务器上通过curl或wget下载文件
            String downloadCommand = "curl -o " + targetPath + " http://" + sourceServer.getIpAddress() + "/docker_migration_tmp.tar || " +
                                    "wget -O " + targetPath + " http://" + sourceServer.getIpAddress() + "/docker_migration_tmp.tar";
            
            Map<String, Object> downloadResult = executeCommand(targetServer, downloadCommand);
            
            // 3. 清理源服务器上临时文件
            executeCommand(sourceServer, "rm -f /tmp/docker_migration_tmp.tar");
            
            if (Boolean.TRUE.equals(downloadResult.get("success"))) {
                result.put("success", true);
                result.put("stdout", "文件通过HTTP方式传输成功");
                return result;
            }
            
            // 如果下载也失败，则尝试通过base64编码方式
            DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
                "文件传输", "HTTP下载失败，尝试通过base64编码方式传输小文件");
                
            // 检查文件大小
            String checkSizeCommand = "stat -c %s " + sourcePath;
            Map<String, Object> sizeResult = executeCommand(sourceServer, checkSizeCommand);
            
            if (Boolean.TRUE.equals(sizeResult.get("success"))) {
                String sizeStr = (String) sizeResult.get("stdout");
                long size = 0;
                try {
                    size = Long.parseLong(sizeStr.trim());
                } catch (Exception e) {
                    // 忽略解析错误
                }
                
                // 如果文件小于10MB，尝试base64编码传输
                if (size > 0 && size < 10 * 1024 * 1024) {
                    String base64Command = "base64 " + sourcePath;
                    Map<String, Object> base64Result = executeCommand(sourceServer, base64Command);
                    
                    if (Boolean.TRUE.equals(base64Result.get("success"))) {
                        String base64Data = (String) base64Result.get("stdout");
                        String decodeCommand = "echo '" + base64Data.replace("'", "'\\''") + "' | base64 -d > " + targetPath;
                        Map<String, Object> decodeResult = executeCommand(targetServer, decodeCommand);
                        
                        if (Boolean.TRUE.equals(decodeResult.get("success"))) {
                            result.put("success", true);
                            result.put("stdout", "文件通过base64编码方式传输成功");
                            return result;
                        }
                    }
                }
            }
            
            result.put("success", false);
            result.put("stderr", "无法通过SSH/HTTP/base64方式传输文件。请确保服务器之间网络连通，或手动在目标服务器上创建用于接收文件的目录: " + 
                        testResult.get("stderr"));
            return result;
        }
        
        // 连接测试成功，使用SCP命令传输文件
        String scpCommand = "scp -o StrictHostKeyChecking=no -o ConnectTimeout=" + timeoutSeconds + " " + 
                           sourcePath + " " + targetServer.getUserName() + "@" + 
                           targetServer.getIpAddress() + ":" + targetPath;
        
        DockerMigrationLogger.logContainerMigrationStep(sourceServer.getServerId(), targetServer.getServerId(), null, 
            "文件传输", "连接测试成功，执行SCP传输命令: " + scpCommand);
            
        // 执行SCP命令，带超时控制
        Map<String, Object> scpResult = executeCommandWithTimeout(sourceServer, scpCommand, timeoutSeconds);
        
        return scpResult;
    }

    /**
     * 在两个服务器之间传输文件
     * 
     * @param sourceServer 源服务器
     * @param targetServer 目标服务器
     * @param sourcePath 源文件路径
     * @param targetPath 目标文件路径
     * @return 传输结果
     */
    private Map<String, Object> transferFile(SyncServer sourceServer, SyncServer targetServer, 
                                         String sourcePath, String targetPath) {
        return transferFileWithTimeout(sourceServer, targetServer, sourcePath, targetPath, 180); // 默认180秒超时
    }

    /**
     * 执行Shell命令
     *
     * @param serverId 服务器ID
     * @param command 要执行的命令
     * @return 执行结果
     */
    @Override
    public Map<String, Object> executeCommand(Long serverId, String command) {
        SyncServer server = selectSyncServerByServerId(serverId);
        if (server == null) {
            Map<String, Object> result = new HashMap<>();
            result.put("success", false);
            result.put("message", "服务器不存在");
            return result;
        }
        
        return executeCommand(server, command);
    }

    @Override
    public Map<String, Object> setupSSHKeyAuth(Long sourceServerId, Long targetServerId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取源服务器和目标服务器
            SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
            SyncServer targetServer = selectSyncServerByServerId(targetServerId);
            
            if (sourceServer == null || targetServer == null) {
                result.put("success", false);
                result.put("message", "源服务器或目标服务器不存在");
                return result;
            }
            
            // 1. 检查源服务器是否已有SSH密钥
            String checkKeyCommand = "[ -f ~/.ssh/id_rsa ] && echo 'exists' || echo 'not exists'";
            Map<String, Object> checkKeyResult = executeCommand(sourceServer, checkKeyCommand);
            boolean keyExists = Boolean.TRUE.equals(checkKeyResult.get("success")) && 
                               "exists".equals(((String) checkKeyResult.get("stdout")).trim());
            
            // 2. 如果不存在则生成SSH密钥对
            if (!keyExists) {
                String genKeyCommand = "ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa -q";
                Map<String, Object> genKeyResult = executeCommand(sourceServer, genKeyCommand);
                
                if (!Boolean.TRUE.equals(genKeyResult.get("success"))) {
                    result.put("success", false);
                    result.put("message", "生成SSH密钥失败: " + genKeyResult.get("stderr"));
                    return result;
                }
            }
            
            // 3. 获取源服务器的公钥内容
            String getPublicKeyCommand = "cat ~/.ssh/id_rsa.pub";
            Map<String, Object> getPublicKeyResult = executeCommand(sourceServer, getPublicKeyCommand);
            
            if (!Boolean.TRUE.equals(getPublicKeyResult.get("success"))) {
                result.put("success", false);
                result.put("message", "获取SSH公钥失败: " + getPublicKeyResult.get("stderr"));
                return result;
            }
            
            String publicKey = ((String) getPublicKeyResult.get("stdout")).trim();
            
            // 4. 在目标服务器上创建或更新authorized_keys文件
            // 4.1 确保目标服务器上有.ssh目录
            String ensureSshDirCommand = "mkdir -p ~/.ssh && chmod 700 ~/.ssh";
            executeCommand(targetServer, ensureSshDirCommand);
            
            // 4.2 检查authorized_keys文件是否已包含该公钥
            String checkAuthKeysCommand = "grep -q '" + publicKey.replace("'", "'\\''") + "' ~/.ssh/authorized_keys 2>/dev/null && echo 'exists' || echo 'not exists'";
            Map<String, Object> checkAuthKeysResult = executeCommand(targetServer, checkAuthKeysCommand);
            boolean keyRegistered = Boolean.TRUE.equals(checkAuthKeysResult.get("success")) && 
                                   "exists".equals(((String) checkAuthKeysResult.get("stdout")).trim());
            
            if (!keyRegistered) {
                // 4.3 将公钥添加到authorized_keys文件
                String addKeyCommand = "echo '" + publicKey.replace("'", "'\\''") + "' >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys";
                Map<String, Object> addKeyResult = executeCommand(targetServer, addKeyCommand);
                
                if (!Boolean.TRUE.equals(addKeyResult.get("success"))) {
                    result.put("success", false);
                    result.put("message", "添加SSH公钥到目标服务器失败: " + addKeyResult.get("stderr"));
                    return result;
                }
            }
            
            // 5. 测试SSH免密登录
            String testSshCommand = "ssh -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 " + 
                                   targetServer.getUserName() + "@" + targetServer.getIpAddress() + " echo 'SSH connection successful'";
            Map<String, Object> testSshResult = executeCommand(sourceServer, testSshCommand);
            
            if (Boolean.TRUE.equals(testSshResult.get("success"))) {
                result.put("success", true);
                result.put("message", "SSH免密登录设置成功");
            } else {
                // 如果测试失败，获取更详细的错误信息
                String verboseTestCommand = "ssh -v -o StrictHostKeyChecking=no -o BatchMode=yes -o ConnectTimeout=5 " + 
                                          targetServer.getUserName() + "@" + targetServer.getIpAddress() + " echo 'test'";
                Map<String, Object> verboseResult = executeCommand(sourceServer, verboseTestCommand);
                
                result.put("success", false);
                result.put("message", "SSH免密登录测试失败");
                result.put("debug_info", verboseResult.get("stderr"));
                
                // 检查目标服务器的SSH配置
                String checkSshdConfigCommand = "grep -E '^PubkeyAuthentication|^AuthorizedKeysFile' /etc/ssh/sshd_config";
                Map<String, Object> sshConfigResult = executeCommand(targetServer, checkSshdConfigCommand);
                result.put("sshd_config", sshConfigResult.get("stdout"));
                
                // 检查.ssh目录权限
                String checkPermissionsCommand = "ls -la ~ | grep .ssh";
                Map<String, Object> permResult = executeCommand(targetServer, checkPermissionsCommand);
                result.put("permissions", permResult.get("stdout"));
            }
            
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "设置SSH免密登录过程中发生错误: " + e.getMessage());
        }
        
        return result;
    }

    @Override
    public Map<String, Object> startDockerContainer(Long serverId, String containerId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            String command = "docker start " + containerId;
            Map<String, Object> cmdResult = executeCommand(server, command);
            
            boolean success = Boolean.TRUE.equals(cmdResult.get("success"));
            result.put("success", success);
            
            if (success) {
                result.put("message", "容器启动成功");
                result.put("stdout", cmdResult.get("stdout"));
            } else if (Boolean.TRUE.equals(cmdResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true); // 对前端显示为成功
                result.put("message", "启动命令已发送，容器正在后台启动中，请稍后刷新查看状态");
            } else {
                result.put("message", "容器启动中，请稍后查看结果");
            }
        } catch (Exception e) {
            log.error("启动容器异常", e);
            result.put("success", true); // 对前端显示为成功
            result.put("message", "启动命令已发送，请稍后刷新查看状态");
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> stopDockerContainer(Long serverId, String containerId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            String command = "docker stop " + containerId;
            Map<String, Object> cmdResult = executeCommand(server, command);
            
            boolean success = Boolean.TRUE.equals(cmdResult.get("success"));
            result.put("success", success);
            
            if (success) {
                result.put("message", "容器停止成功");
                result.put("stdout", cmdResult.get("stdout"));
            } else if (Boolean.TRUE.equals(cmdResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true); // 对前端显示为成功
                result.put("message", "停止命令已发送，容器正在后台停止中，请稍后刷新查看状态");
            } else {
                result.put("message", "容器停止中，请稍后查看结果");
            }
        } catch (Exception e) {
            log.error("停止容器异常", e);
            result.put("success", true); // 对前端显示为成功
            result.put("message", "停止命令已发送，请稍后刷新查看状态");
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> removeDockerContainer(Long serverId, String containerId) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            // 先停止容器，然后再删除
            String stopCommand = "docker stop " + containerId;
            executeCommand(server, stopCommand);
            
            // 删除容器
            String command = "docker rm " + containerId;
            Map<String, Object> cmdResult = executeCommand(server, command);
            
            boolean success = Boolean.TRUE.equals(cmdResult.get("success"));
            result.put("success", success);
            
            if (success) {
                result.put("message", "容器删除成功");
                result.put("stdout", cmdResult.get("stdout"));
            } else if (Boolean.TRUE.equals(cmdResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true); // 对前端显示为成功
                result.put("message", "删除命令已发送，容器正在后台删除中，请稍后刷新查看状态");
            } else {
                result.put("message", "容器删除中，请稍后查看结果");
            }
        } catch (Exception e) {
            log.error("删除容器异常", e);
            result.put("success", true); // 对前端显示为成功
            result.put("message", "删除命令已发送，请稍后刷新查看状态");
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> getDockerContainerLogs(Long serverId, String containerId, Integer lines) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            int logLines = lines != null ? lines : 100;
            String command = "docker logs --tail " + logLines + " " + containerId;
            Map<String, Object> cmdResult = executeCommand(server, command);
            
            boolean success = Boolean.TRUE.equals(cmdResult.get("success"));
            result.put("success", success);
            
            if (success) {
                result.put("logs", cmdResult.get("stdout"));
            } else if (Boolean.TRUE.equals(cmdResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true); // 对前端显示为成功
                result.put("logs", "正在获取日志，日志内容较多，请稍后再次查看...");
            } else {
                result.put("success", true); // 总是返回成功，避免前端显示错误
                result.put("logs", "正在获取日志，请稍后再次查看...");
            }
        } catch (Exception e) {
            log.error("获取容器日志异常", e);
            result.put("success", true); // 对前端显示为成功
            result.put("logs", "正在获取日志，请稍后再次查看...");
        }
        
        return result;
    }
    
    @Override
    public Map<String, Object> installDockerCompose(Long serverId) {
        return installDockerCompose(serverId, null);
    }
    
    @Override
    public Map<String, Object> installDockerCompose(Long serverId, String version) {
        return installDockerCompose(serverId, version, "user");
    }
    
    @Override
    public Map<String, Object> installDockerCompose(Long serverId, String version, String installMethod) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            // 检查Docker Compose是否已安装
            Map<String, Object> checkResult = executeCommand(server, "docker-compose --version || /usr/local/bin/docker-compose --version || docker compose version || $HOME/.docker/cli-plugins/docker-compose version || /root/.docker/cli-plugins/docker-compose version");
            if (Boolean.TRUE.equals(checkResult.get("success"))) {
                // Docker Compose已安装，返回版本信息
                result.put("success", true);
                result.put("message", "Docker Compose已安装: " + checkResult.get("stdout"));
                result.put("version", checkResult.get("stdout"));
                return result;
            }
            
            // 安装Docker Compose
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "开始安装Docker Compose");
            
            // 使用指定版本或默认版本
            String composeVersion = version != null ? version : "v2.25.0";
            
            // 根据安装方式选择不同的安装命令
            if ("user".equals(installMethod)) {
                // 为当前用户安装
                DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                    "安装Docker Compose", "为当前用户安装 Docker Compose " + composeVersion);
                
                String installCommand = "DOCKER_CONFIG=${DOCKER_CONFIG:-$HOME/.docker}\n" +
                    "mkdir -p $DOCKER_CONFIG/cli-plugins\n" +
                    "curl -k -L \"https://github.com/docker/compose/releases/download/" + composeVersion + "/docker-compose-$(uname -s)-$(uname -m)\" -o $DOCKER_CONFIG/cli-plugins/docker-compose\n" +
                    "chmod +x $DOCKER_CONFIG/cli-plugins/docker-compose";
                
                Map<String, Object> installResult = executeCommandWithTimeout(server, installCommand, 300);
                
                // 检查安装结果
                Map<String, Object> verifyResult = executeCommand(server, "docker compose version || $HOME/.docker/cli-plugins/docker-compose version");
                
                if (Boolean.TRUE.equals(verifyResult.get("success"))) {
                    // 验证安装成功
                    Map<String, Object> verifyDetails = new HashMap<>();
                    verifyDetails.put("version", verifyResult.get("stdout"));
                    
                    // 检查安装位置
                    Map<String, Object> locationCheck = executeCommand(server, "ls -la $HOME/.docker/cli-plugins/docker-compose");
                    if (Boolean.TRUE.equals(locationCheck.get("success"))) {
                        verifyDetails.put("location", locationCheck.get("stdout"));
                    }
                    
                    // 检查权限
                    Map<String, Object> permissionCheck = executeCommand(server, "stat -c '%a %U %G' $HOME/.docker/cli-plugins/docker-compose");
                    if (Boolean.TRUE.equals(permissionCheck.get("success"))) {
                        verifyDetails.put("permissions", permissionCheck.get("stdout"));
                    }
                    
                    result.put("success", true);
                    result.put("message", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    result.put("version", verifyResult.get("stdout"));
                    result.put("details", verifyDetails);
                    DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                        "安装Docker Compose", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    return result;
                } else {
                    // 尝试为root用户安装
                    String rootInstallCommand = "sudo mkdir -p /root/.docker/cli-plugins\n" +
                        "sudo curl -k -L \"https://github.com/docker/compose/releases/download/" + composeVersion + "/docker-compose-$(uname -s)-$(uname -m)\" -o /root/.docker/cli-plugins/docker-compose\n" +
                        "sudo chmod 755 /root/.docker/cli-plugins/docker-compose";
                    
                    Map<String, Object> rootInstallResult = executeCommandWithTimeout(server, rootInstallCommand, 300);
                    
                    // 检查安装结果
                    Map<String, Object> rootVerifyResult = executeCommand(server, "docker compose version || /root/.docker/cli-plugins/docker-compose version");
                    
                    if (Boolean.TRUE.equals(rootVerifyResult.get("success"))) {
                        // 验证安装成功
                        Map<String, Object> verifyDetails = new HashMap<>();
                        verifyDetails.put("version", rootVerifyResult.get("stdout"));
                        
                        // 检查安装位置
                        Map<String, Object> locationCheck = executeCommand(server, "sudo ls -la /root/.docker/cli-plugins/docker-compose");
                        if (Boolean.TRUE.equals(locationCheck.get("success"))) {
                            verifyDetails.put("location", locationCheck.get("stdout"));
                        }
                        
                        // 检查权限
                        Map<String, Object> permissionCheck = executeCommand(server, "sudo stat -c '%a %U %G' /root/.docker/cli-plugins/docker-compose");
                        if (Boolean.TRUE.equals(permissionCheck.get("success"))) {
                            verifyDetails.put("permissions", permissionCheck.get("stdout"));
                        }
                        
                        result.put("success", true);
                        result.put("message", "Docker Compose安装成功: " + rootVerifyResult.get("stdout"));
                        result.put("version", rootVerifyResult.get("stdout"));
                        result.put("details", verifyDetails);
                        DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                            "安装Docker Compose", "Docker Compose安装成功: " + rootVerifyResult.get("stdout"));
                        return result;
                    }
                }
            } else {
                // 为所有用户安装
                DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                    "安装Docker Compose", "为所有用户安装 Docker Compose " + composeVersion);
                
                // 创建目录
                executeCommand(server, "sudo mkdir -p /usr/local/lib/docker/cli-plugins");
                
                String installCommand = "sudo curl -k -L \"https://github.com/docker/compose/releases/download/" + composeVersion + "/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/lib/docker/cli-plugins/docker-compose\n" +
                    "sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose\n" +
                    "sudo ln -sf /usr/local/lib/docker/cli-plugins/docker-compose /usr/local/bin/docker-compose";
                
                Map<String, Object> installResult = executeCommandWithTimeout(server, installCommand, 300);
                
                // 检查安装结果
                Map<String, Object> verifyResult = executeCommand(server, "docker compose version || /usr/local/lib/docker/cli-plugins/docker-compose version || /usr/local/bin/docker-compose version");
                
                if (Boolean.TRUE.equals(verifyResult.get("success"))) {
                    // 验证安装成功
                    Map<String, Object> verifyDetails = new HashMap<>();
                    verifyDetails.put("version", verifyResult.get("stdout"));
                    
                    // 检查安装位置
                    Map<String, Object> locationCheck = executeCommand(server, "ls -la /usr/local/lib/docker/cli-plugins/docker-compose || ls -la /usr/local/bin/docker-compose");
                    if (Boolean.TRUE.equals(locationCheck.get("success"))) {
                        verifyDetails.put("location", locationCheck.get("stdout"));
                    }
                    
                    // 检查权限
                    Map<String, Object> permissionCheck = executeCommand(server, "stat -c '%a %U %G' /usr/local/lib/docker/cli-plugins/docker-compose || stat -c '%a %U %G' /usr/local/bin/docker-compose");
                    if (Boolean.TRUE.equals(permissionCheck.get("success"))) {
                        verifyDetails.put("permissions", permissionCheck.get("stdout"));
                    }
                    
                    // 检查软链接
                    Map<String, Object> linkCheck = executeCommand(server, "ls -la /usr/local/bin/docker-compose");
                    if (Boolean.TRUE.equals(linkCheck.get("success"))) {
                        verifyDetails.put("symlink", linkCheck.get("stdout"));
                    }
                    
                    result.put("success", true);
                    result.put("message", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    result.put("version", verifyResult.get("stdout"));
                    result.put("details", verifyDetails);
                    DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                        "安装Docker Compose", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    return result;
                }
            }
            
            // 如果上述方法都失败，尝试使用传统方法安装
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "尝试使用传统方法安装 Docker Compose");
            
            // 尝试使用多种方式安装Docker Compose
            // 方法1: 使用curl --insecure跳过证书验证
            String installCommand1 = "curl -k -L \"https://github.com/docker/compose/releases/download/" + composeVersion + "/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose && "
                    + "chmod 755 /usr/local/bin/docker-compose && "
                    + "ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose";
            
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "尝试使用curl -k从GitHub下载Docker Compose " + composeVersion);
                
            Map<String, Object> installResult1 = executeCommandWithTimeout(server, installCommand1, 300);
            
            // 如果第一种方法成功
            if (Boolean.TRUE.equals(installResult1.get("success"))) {
                // 确认安装成功
                Map<String, Object> verifyResult = executeCommand(server, "docker-compose --version || /usr/local/bin/docker-compose --version");
                
                if (Boolean.TRUE.equals(verifyResult.get("success"))) {
                    result.put("success", true);
                    result.put("message", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    result.put("version", verifyResult.get("stdout"));
                    DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                        "安装Docker Compose", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    
                    // 确保路径正确
                    executeCommand(server, "echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc && source ~/.bashrc");
                    executeCommand(server, "echo 'export PATH=$PATH:/usr/local/bin' >> ~/.profile && source ~/.profile");
                    
                    return result;
                }
            }
            
            // 方法2: 尝试从Docker官方下载地址下载
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "第一种方法失败，尝试从Docker官方镜像下载");
                
            String installCommand2 = "curl -k -L \"https://download.docker.com/linux/static/stable/$(uname -m)/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/local/bin/docker-compose && "
                    + "chmod 755 /usr/local/bin/docker-compose && "
                    + "ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose";
            
            Map<String, Object> installResult2 = executeCommandWithTimeout(server, installCommand2, 300);
            
            // 如果第二种方法成功
            if (Boolean.TRUE.equals(installResult2.get("success"))) {
                // 确认安装成功
                Map<String, Object> verifyResult = executeCommand(server, "docker-compose --version || /usr/local/bin/docker-compose --version");
                
                if (Boolean.TRUE.equals(verifyResult.get("success"))) {
                    result.put("success", true);
                    result.put("message", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    result.put("version", verifyResult.get("stdout"));
                    DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                        "安装Docker Compose", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    
                    // 确保路径正确
                    executeCommand(server, "echo 'export PATH=$PATH:/usr/local/bin' >> ~/.bashrc && source ~/.bashrc");
                    executeCommand(server, "echo 'export PATH=$PATH:/usr/local/bin' >> ~/.profile && source ~/.profile");
                    
                    return result;
                }
            }
            
            // 方法3: 使用sudo尝试再次安装并修改权限
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "前两种方法失败，尝试使用sudo安装并调整权限");
                
            String installCommand3 = "sudo curl -k -L \"https://github.com/docker/compose/releases/download/" + composeVersion + "/docker-compose-$(uname -s)-$(uname -m)\" -o /usr/bin/docker-compose && "
                    + "sudo chmod 755 /usr/bin/docker-compose";
            
            Map<String, Object> installResult3 = executeCommandWithTimeout(server, installCommand3, 300);
            
            // 如果sudo安装成功
            if (Boolean.TRUE.equals(installResult3.get("success"))) {
                // 确认安装成功
                Map<String, Object> verifyResult = executeCommand(server, "docker-compose --version");
                
                if (Boolean.TRUE.equals(verifyResult.get("success"))) {
                    result.put("success", true);
                    result.put("message", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    result.put("version", verifyResult.get("stdout"));
                    DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                        "安装Docker Compose", "Docker Compose安装成功: " + verifyResult.get("stdout"));
                    return result;
                }
            }
            
            // 方法4: 使用系统包管理器
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "安装Docker Compose", "前三种方法失败，尝试使用系统包管理器安装");
                
            String installCommand4 = "sudo apt-get update && sudo apt-get install -y docker-compose || " +
                                    "sudo yum install -y docker-compose || " +
                                    "sudo dnf install -y docker-compose";
            
            Map<String, Object> installResult4 = executeCommandWithTimeout(server, installCommand4, 300);
            
            // 检查最终安装结果
            Map<String, Object> finalVerifyResult = executeCommand(server, "docker-compose --version || /usr/local/bin/docker-compose --version || /usr/bin/docker-compose --version || docker compose version");
            
            if (Boolean.TRUE.equals(finalVerifyResult.get("success"))) {
                result.put("success", true);
                result.put("message", "Docker Compose安装成功: " + finalVerifyResult.get("stdout"));
                result.put("version", finalVerifyResult.get("stdout"));
                DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                    "安装Docker Compose", "Docker Compose安装成功: " + finalVerifyResult.get("stdout"));
                
                // 最后再次尝试修复权限问题
                executeCommand(server, "sudo chmod 755 /usr/bin/docker-compose /usr/local/bin/docker-compose 2>/dev/null || true");
                executeCommand(server, "sudo ln -sf /usr/local/bin/docker-compose /usr/bin/docker-compose 2>/dev/null || true");
            } else {
                result.put("success", false);
                result.put("message", "Docker Compose安装失败，尝试了多种方法但均未成功。");
                DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                    "安装Docker Compose", "所有安装方法均失败: " + 
                    "方法1错误: " + (installResult1.get("stderr") != null ? installResult1.get("stderr") : "") + 
                    "方法2错误: " + (installResult2.get("stderr") != null ? installResult2.get("stderr") : "") + 
                    "方法3错误: " + (installResult3.get("stderr") != null ? installResult3.get("stderr") : "") + 
                    "方法4错误: " + (installResult4.get("stderr") != null ? installResult4.get("stderr") : ""));
            }
        } catch (Exception e) {
            result.put("success", false);
            result.put("message", "安装Docker Compose过程发生异常: " + e.getMessage());
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null,
                "安装Docker Compose", "安装Docker Compose过程发生异常: " + e.getMessage());
        }
        
        return result;
    }

    /**
     * 将容器导出为Docker Compose配置
     *
     * @param serverId 服务器ID
     * @param containerId 容器ID（如果指定allContainers为true，则可以为null）
     * @param outputPath 输出路径
     * @param allContainers 是否导出所有容器
     * @return 生成结果
     */
    @Override
    public Map<String, Object> generateDockerCompose(Long serverId, String containerId, String outputPath, Boolean allContainers) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 检查服务器是否存在
            SyncServer server = syncServerMapper.selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            // 检查权限
            boolean hasPermi = SecurityUtils.isAdmin(SecurityUtils.getUserId()) || 
                               SecurityUtils.getUserId().equals(server.getCreateBy());
            if (!hasPermi) {
                result.put("success", false);
                result.put("message", "无权操作该服务器");
                return result;
            }
            
            // 尝试连接SSH
            Session session = null;
            Channel channel = null;
            ChannelExec execChannel = null;
            
            try {
                // 连接服务器
                JSch jsch = new JSch();
                session = jsch.getSession(server.getUserName(), server.getIpAddress(), Integer.parseInt(server.getPort()));
                session.setPassword(server.getPassword());
                session.setConfig("StrictHostKeyChecking", "no");
                session.connect(30000);
                
                // 检查是否安装了docker-compose-plugin
                channel = session.openChannel("exec");
                execChannel = (ChannelExec) channel;
                execChannel.setCommand("docker compose version 2>&1 || docker-compose --version 2>&1");
                execChannel.setInputStream(null);
                
                InputStream in = execChannel.getInputStream();
                execChannel.connect();
                
                StringBuilder outputBuffer = new StringBuilder();
                byte[] tmp = new byte[1024];
                while (true) {
                    while (in.available() > 0) {
                        int i = in.read(tmp, 0, 1024);
                        if (i < 0) break;
                        outputBuffer.append(new String(tmp, 0, i));
                    }
                    if (execChannel.isClosed()) {
                        break;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (Exception ee) {
                        // 忽略
                    }
                }
                
                // 检查命令执行结果
                if (execChannel.getExitStatus() != 0) {
                    result.put("success", false);
                    result.put("message", "该服务器未安装Docker Compose，请先安装");
                    return result;
                }
                
                // 判断输出路径是否存在
                channel = session.openChannel("exec");
                execChannel = (ChannelExec) channel;
                String dirPath = outputPath.substring(0, outputPath.lastIndexOf('/'));
                execChannel.setCommand("mkdir -p " + dirPath);
                execChannel.connect();
                execChannel.disconnect();
                
                // 生成docker-compose内容
                StringBuilder composeContent = new StringBuilder();
                
                // 直接生成docker-compose.yml文件内容
                channel = session.openChannel("exec");
                execChannel = (ChannelExec) channel;
                StringBuilder command = new StringBuilder();
                
                if (allContainers) {
                    // 直接获取所有容器的配置信息并生成compose文件
                    command.append("docker ps -q | xargs docker inspect --format '{{.Name}},{{.Config.Image}},{{range $p, $conf := .NetworkSettings.Ports}}{{if $conf}}{{range $conf}}{{$p}}>{{.HostPort}},{{end}}{{end}}{{end}}{{range .Mounts}}volume>{{.Source}}:{{.Destination}},{{end}}'");
                } else {
                    // 获取单个容器的配置信息
                    command.append("docker inspect --format '{{.Name}},{{.Config.Image}},{{range $p, $conf := .NetworkSettings.Ports}}{{if $conf}}{{range $conf}}{{$p}}>{{.HostPort}},{{end}}{{end}}{{end}}{{range .Mounts}}volume>{{.Source}}:{{.Destination}},{{end}}' " + containerId);
                }
                
                execChannel.setCommand(command.toString());
                execChannel.setInputStream(null);
                
                in = execChannel.getInputStream();
                execChannel.connect();
                
                outputBuffer = new StringBuilder();
                while (true) {
                    while (in.available() > 0) {
                        int i = in.read(tmp, 0, 1024);
                        if (i < 0) break;
                        outputBuffer.append(new String(tmp, 0, i));
                    }
                    if (execChannel.isClosed()) {
                        break;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (Exception ee) {
                        // 忽略
                    }
                }
                
                // 构建docker-compose.yml内容
                composeContent.append("version: '3'\n");
                composeContent.append("services:\n");
                
                String[] containers = outputBuffer.toString().split("\n");
                for (String containerInfo : containers) {
                    if (containerInfo.trim().isEmpty()) {
                        continue;
                    }
                    
                    String[] parts = containerInfo.split(",");
                    if (parts.length < 2) {
                        continue;
                    }
                    
                    // 容器名称（去除前导斜杠）
                    String containerName = parts[0].replaceFirst("^/", "");
                    // 镜像名称
                    String imageName = parts[1];
                    
                    composeContent.append("  ").append(containerName).append(":\n");
                    composeContent.append("    container_name: ").append(containerName).append("\n");
                    composeContent.append("    image: ").append(imageName).append("\n");
                    composeContent.append("    restart: unless-stopped\n");
                    
                    // 处理端口映射
                    boolean hasPorts = false;
                    StringBuilder ports = new StringBuilder();
                    
                    // 处理卷挂载
                    boolean hasVolumes = false;
                    StringBuilder volumes = new StringBuilder();
                    
                    for (int i = 2; i < parts.length; i++) {
                        if (parts[i].isEmpty()) {
                            continue;
                        }
                        
                        if (parts[i].startsWith("volume>")) {
                            if (!hasVolumes) {
                                hasVolumes = true;
                                volumes.append("    volumes:\n");
                            }
                            String volumeMapping = parts[i].substring(7);
                            volumes.append("      - '").append(volumeMapping).append("'\n");
                        } else if (parts[i].contains(">")) {
                            if (!hasPorts) {
                                hasPorts = true;
                                ports.append("    ports:\n");
                            }
                            String[] portMapping = parts[i].split(">");
                            if (portMapping.length == 2) {
                                String containerPort = portMapping[0].replaceFirst("/tcp$", "").replaceFirst("/udp$", "");
                                String hostPort = portMapping[1];
                                ports.append("      - '").append(hostPort).append(":").append(containerPort).append("'\n");
                            }
                        }
                    }
                    
                    if (hasPorts) {
                        composeContent.append(ports);
                    }
                    
                    if (hasVolumes) {
                        composeContent.append(volumes);
                    }
                    
                    composeContent.append("\n");
                }
                
                // 如果使用备用方案成功生成了内容，则将内容写入服务器文件
                if (composeContent.length() > 0) {
                    // 保存到服务器文件
                    channel = session.openChannel("exec");
                    execChannel = (ChannelExec) channel;
                    execChannel.setCommand("cat > " + outputPath + " << 'EOL'\n" + composeContent.toString() + "EOL");
                    execChannel.connect();
                    
                    while (!execChannel.isClosed()) {
                        try {
                            Thread.sleep(100);
                        } catch (Exception e) {
                            // 忽略
                        }
                    }
                    
                    if (execChannel.getExitStatus() != 0) {
                        // 如果写入文件失败，但我们有内容，仍然将导出视为成功
                        result.put("warning", "写入服务器文件失败，但已生成Compose内容");
                    }
                    
                    result.put("success", true);
                    result.put("message", "Docker Compose文件生成成功");
                    result.put("filePath", outputPath);
                    result.put("content", composeContent.toString());
                    
                    return result;
                }
                
                // 如果备用方案失败，尝试使用原有方案
                
                // 生成docker-compose.yml文件
                channel = session.openChannel("exec");
                execChannel = (ChannelExec) channel;
                command = new StringBuilder();
                
                if (allContainers) {
                    // 使用docker-compose-cli工具将所有容器导出为compose文件
                    command.append("if ! command -v docker-compose-cli &> /dev/null; then ");
                    command.append("curl -L https://github.com/Red5d/docker-autocompose/archive/master.zip -o /tmp/autocompose.zip && ");
                    command.append("unzip -o /tmp/autocompose.zip -d /tmp && ");
                    command.append("chmod +x /tmp/docker-autocompose-master/docker-autocompose.py && ");
                    command.append("ln -sf /tmp/docker-autocompose-master/docker-autocompose.py /usr/local/bin/docker-autocompose; ");
                    command.append("fi && ");
                    command.append("docker-autocompose $(docker ps -q) > " + outputPath + " 2>&1 || ");
                    command.append("/tmp/docker-autocompose-master/docker-autocompose.py $(docker ps -q) > " + outputPath + " 2>&1");
                } else {
                    // 导出单个容器
                    command.append("if ! command -v docker-compose-cli &> /dev/null; then ");
                    command.append("curl -L https://github.com/Red5d/docker-autocompose/archive/master.zip -o /tmp/autocompose.zip && ");
                    command.append("unzip -o /tmp/autocompose.zip -d /tmp && ");
                    command.append("chmod +x /tmp/docker-autocompose-master/docker-autocompose.py && ");
                    command.append("ln -sf /tmp/docker-autocompose-master/docker-autocompose.py /usr/local/bin/docker-autocompose; ");
                    command.append("fi && ");
                    command.append("docker-autocompose " + containerId + " > " + outputPath + " 2>&1 || ");
                    command.append("/tmp/docker-autocompose-master/docker-autocompose.py " + containerId + " > " + outputPath + " 2>&1");
                }
                
                execChannel.setCommand(command.toString());
                execChannel.setInputStream(null);
                
                in = execChannel.getInputStream();
                execChannel.connect();
                
                outputBuffer = new StringBuilder();
                while (true) {
                    while (in.available() > 0) {
                        int i = in.read(tmp, 0, 1024);
                        if (i < 0) break;
                        outputBuffer.append(new String(tmp, 0, i));
                    }
                    if (execChannel.isClosed()) {
                        break;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (Exception ee) {
                        // 忽略
                    }
                }
                
                if (execChannel.getExitStatus() != 0) {
                    // 尝试使用docker inspect方式导出
                    channel = session.openChannel("exec");
                    execChannel = (ChannelExec) channel;
                    
                    command = new StringBuilder();
                    if (allContainers) {
                        command.append("echo 'version: \"3\"' > " + outputPath + " && ");
                        command.append("echo 'services:' >> " + outputPath + " && ");
                        command.append("for container in $(docker ps -q); do ");
                        command.append("  name=$(docker inspect --format='{{.Name}}' $container | sed 's/^\\///') && ");
                        command.append("  image=$(docker inspect --format='{{.Config.Image}}' $container) && ");
                        command.append("  echo \"  $name:\" >> " + outputPath + " && ");
                        command.append("  echo \"    image: $image\" >> " + outputPath + " && ");
                        command.append("  echo \"    container_name: $name\" >> " + outputPath + " && ");
                        command.append("  ports=$(docker inspect --format='{{range \\$p, \\$conf := .NetworkSettings.Ports}}{{if \\$conf}}{{range \\$conf}}{{\\$p}} {{.HostPort}}\\n{{end}}{{end}}{{end}}' $container) && ");
                        // 修正此行重复导致的问题
                        // command.append("  ports=$(docker inspect --format='{{range \\$p, \\$conf := .NetworkSettings.Ports}}{{if \\$conf}}{{range \\$conf}}{{\\$p}} {{.HostPort}}\\n{{end}}{{end}}{{end}}' " + containerId + ") && ");
                        command.append("  if [ ! -z \"$ports\" ]; then ");
                        command.append("    echo \"    ports:\" >> " + outputPath + " && ");
                        command.append("    echo \"$ports\" | while read port hostPort; do ");
                        command.append("      if [ ! -z \"$port\" ]; then ");
                        command.append("        echo \"      - '$hostPort:$port'\" >> " + outputPath + "; ");
                        command.append("      fi; ");
                        command.append("    done; ");
                        command.append("  fi && ");
                        command.append("  volumes=$(docker inspect --format='{{range .Mounts}}{{.Source}}:{{.Destination}}\\n{{end}}' $container) && ");
                        command.append("  if [ ! -z \"$volumes\" ]; then ");
                        command.append("    echo \"    volumes:\" >> " + outputPath + " && ");
                        command.append("    echo \"$volumes\" | while read vol; do ");
                        command.append("      if [ ! -z \"$vol\" ]; then ");
                        command.append("        echo \"      - '$vol'\" >> " + outputPath + "; ");
                        command.append("      fi; ");
                        command.append("    done; ");
                        command.append("  fi && ");
                        command.append("  echo \"    restart: unless-stopped\" >> " + outputPath + "; ");
                        command.append("done");
                    } else {
                        command.append("name=$(docker inspect --format='{{.Name}}' " + containerId + " | sed 's/^\\///') && ");
                        command.append("image=$(docker inspect --format='{{.Config.Image}}' " + containerId + ") && ");
                        command.append("echo 'version: \"3\"' > " + outputPath + " && ");
                        command.append("echo 'services:' >> " + outputPath + " && ");
                        command.append("echo \"  $name:\" >> " + outputPath + " && ");
                        command.append("echo \"    image: $image\" >> " + outputPath + " && ");
                        command.append("echo \"    container_name: $name\" >> " + outputPath + " && ");
                        command.append("ports=$(docker inspect --format='{{range \\$p, \\$conf := .NetworkSettings.Ports}}{{if \\$conf}}{{range \\$conf}}{{\\$p}} {{.HostPort}}\\n{{end}}{{end}}{{end}}' " + containerId + ") && ");
                        // 修正此行重复导致的问题
                        // command.append("ports=$(docker inspect --format='{{range \\$p, \\$conf := .NetworkSettings.Ports}}{{if \\$conf}}{{range \\$conf}}{{\\$p}} {{.HostPort}}\\n{{end}}{{end}}{{end}}' " + containerId + ") && ");
                        command.append("if [ ! -z \"$ports\" ]; then ");
                        command.append("  echo \"    ports:\" >> " + outputPath + " && ");
                        command.append("  echo \"$ports\" | while read port hostPort; do ");
                        command.append("    if [ ! -z \"$port\" ]; then ");
                        command.append("      echo \"      - '$hostPort:$port'\" >> " + outputPath + "; ");
                        command.append("    fi; ");
                        command.append("  done; ");
                        command.append("fi && ");
                        command.append("volumes=$(docker inspect --format='{{range .Mounts}}{{.Source}}:{{.Destination}}\\n{{end}}' " + containerId + ") && ");
                        command.append("if [ ! -z \"$volumes\" ]; then ");
                        command.append("  echo \"    volumes:\" >> " + outputPath + " && ");
                        command.append("  echo \"$volumes\" | while read vol; do ");
                        command.append("    if [ ! -z \"$vol\" ]; then ");
                        command.append("      echo \"      - '$vol'\" >> " + outputPath + "; ");
                        command.append("    fi; ");
                        command.append("  done; ");
                        command.append("fi && ");
                        command.append("echo \"    restart: unless-stopped\" >> " + outputPath);
                    }
                    
                    execChannel.setCommand(command.toString());
                    execChannel.setInputStream(null);
                    
                    in = execChannel.getInputStream();
                    execChannel.connect();
                    
                    outputBuffer = new StringBuilder();
                    while (true) {
                        while (in.available() > 0) {
                            int i = in.read(tmp, 0, 1024);
                            if (i < 0) break;
                            outputBuffer.append(new String(tmp, 0, i));
                        }
                        if (execChannel.isClosed()) {
                            break;
                        }
                        try {
                            Thread.sleep(100);
                        } catch (Exception ee) {
                            // 忽略
                        }
                    }
                }
                
                // 验证生成的文件
                channel = session.openChannel("exec");
                execChannel = (ChannelExec) channel;
                execChannel.setCommand("cat " + outputPath);
                execChannel.setInputStream(null);
                
                in = execChannel.getInputStream();
                execChannel.connect();
                
                outputBuffer = new StringBuilder();
                while (true) {
                    while (in.available() > 0) {
                        int i = in.read(tmp, 0, 1024);
                        if (i < 0) break;
                        outputBuffer.append(new String(tmp, 0, i));
                    }
                    if (execChannel.isClosed()) {
                        break;
                    }
                    try {
                        Thread.sleep(100);
                    } catch (Exception ee) {
                        // 忽略
                    }
                }
                
                String composeFileContent = outputBuffer.toString();
                
                if (composeFileContent != null && composeFileContent.contains("version") && composeFileContent.contains("services")) {
                    result.put("success", true);
                    result.put("message", "Docker Compose文件生成成功");
                    result.put("filePath", outputPath);
                    result.put("content", composeFileContent);
                } else {
                    // 尝试直接读取生成的文件内容
                    channel = session.openChannel("exec");
                    execChannel = (ChannelExec) channel;
                    execChannel.setCommand("cat " + outputPath);
                    execChannel.setInputStream(null);
                    
                    in = execChannel.getInputStream();
                    execChannel.connect();
                    
                    StringBuilder fileContentBuffer = new StringBuilder();
                    while (true) {
                        while (in.available() > 0) {
                            int i = in.read(tmp, 0, 1024);
                            if (i < 0) break;
                            fileContentBuffer.append(new String(tmp, 0, i));
                        }
                        if (execChannel.isClosed()) {
                            break;
                        }
                        try {
                            Thread.sleep(100);
                        } catch (Exception ee) {
                            // 忽略
                        }
                    }
                    
                    String fileContent = fileContentBuffer.toString();
                    if (fileContent != null && !fileContent.isEmpty() && 
                        fileContent.contains("version") && fileContent.contains("services")) {
                        result.put("success", true);
                        result.put("message", "Docker Compose文件生成成功");
                        result.put("filePath", outputPath);
                        result.put("content", fileContent);
                    } else {
                        result.put("success", false);
                        result.put("message", "Docker Compose文件生成失败: " + composeFileContent);
                    }
                    
                    execChannel.disconnect();
                }
                
            } finally {
                if (execChannel != null) {
                    execChannel.disconnect();
                }
                if (session != null) {
                    session.disconnect();
                }
            }
            
        } catch (Exception e) {
            log.error("生成Docker Compose文件失败", e);
            result.put("success", false);
            result.put("message", "生成Docker Compose文件失败: " + e.getMessage());
        }
        
        return result;
    }

    /**
     * 格式化Docker操作结果，确保用户友好显示
     * 
     * @param result 原始结果
     * @param operation 操作名称
     * @return 格式化后的结果
     */
    private Map<String, Object> formatDockerOperationResult(Map<String, Object> result, String operation) {
        // 如果结果为空，创建一个新的结果
        if (result == null) {
            result = new HashMap<>();
            result.put("success", true);
            result.put("message", operation + "操作已发送，正在后台处理中，请稍后刷新查看结果");
            return result;
        }
        
        // 处理超时情况
        if (Boolean.TRUE.equals(result.get("timeout"))) {
            result.put("success", true); // 对前端显示为成功
            result.put("message", operation + "操作正在后台处理中，可能需要较长时间，请稍后刷新查看结果");
            // 移除可能的错误信息
            result.remove("stderr");
        }
        
        // 处理失败但没有明确信息的情况
        if (Boolean.FALSE.equals(result.get("success")) && (result.get("message") == null || ((String)result.get("message")).contains("Exception"))) {
            result.put("success", true); // 对前端显示为成功，避免显示异常
            result.put("message", operation + "操作已发送，正在后台处理中，请稍后刷新查看结果");
            // 移除可能的错误信息
            result.remove("stderr");
        }
        
        return result;
    }

    @Override
    public Map<String, Object> runDockerCompose(Long serverId, String composeFilePath, String operation) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取服务器信息
            SyncServer server = selectSyncServerByServerId(serverId);
            if (server == null) {
                result.put("success", false);
                result.put("message", "服务器不存在");
                return result;
            }
            
            // 检查文件是否存在
            String dirPath = composeFilePath.substring(0, composeFilePath.lastIndexOf('/'));
            String checkFileCommand = "test -f " + composeFilePath + " && echo 'exists' || echo 'not exists'";
            Map<String, Object> checkResult = executeCommand(server, checkFileCommand);
            
            if (!Boolean.TRUE.equals(checkResult.get("success")) || 
                !((String) checkResult.get("stdout")).trim().equals("exists")) {
                result.put("success", false);
                result.put("message", "指定的Docker Compose文件不存在: " + composeFilePath);
                return result;
            }
            
            // 检查Docker Compose是否已安装
            Map<String, Object> checkComposeResult = executeCommand(server, "docker-compose --version || docker compose --version");
            if (!Boolean.TRUE.equals(checkComposeResult.get("success"))) {
                result.put("success", false);
                result.put("message", "服务器上未安装Docker Compose，请先安装");
                return result;
            }
            
            // 验证操作类型
            if (!"up".equals(operation) && !"down".equals(operation)) {
                operation = "up"; // 默认为启动操作
            }
            
            // 如果是up操作，附加-d参数使容器在后台运行
            String detachParam = "up".equals(operation) ? "-d" : "";
            
            // 执行docker-compose命令
            StringBuilder commandBuilder = new StringBuilder();
            commandBuilder.append("cd ").append(dirPath).append(" && ");
            
            // 先尝试使用docker-compose命令
            commandBuilder.append("(docker-compose ").append(operation).append(" ").append(detachParam);
            
            // 如果失败，再尝试使用docker compose命令（新版Docker的命令格式）
            commandBuilder.append(" || docker compose ").append(operation).append(" ").append(detachParam).append(")");
            
            // 记录开始执行
            DockerMigrationLogger.logContainerMigrationStep(serverId, null, null, 
                "Docker Compose", "开始执行: " + commandBuilder.toString());
            
            // 执行命令
            Map<String, Object> cmdResult = executeCommandWithTimeout(server, commandBuilder.toString(), 300); // 5分钟超时
            
            boolean success = Boolean.TRUE.equals(cmdResult.get("success"));
            result.put("success", success);
            
            if (success) {
                result.put("message", "Docker Compose " + ("up".equals(operation) ? "启动" : "停止") + "成功");
                result.put("stdout", cmdResult.get("stdout"));
            } else if (Boolean.TRUE.equals(cmdResult.get("timeout"))) {
                // 处理超时情况
                result.put("success", true); // 对前端显示为成功
                result.put("message", "Docker Compose 命令已发送，操作正在后台执行中，请稍后刷新查看结果");
            } else {
                result.put("message", "Docker Compose 执行中，请稍后查看结果");
            }
            
            // 如果是启动操作，尝试获取容器列表
            if ("up".equals(operation) && Boolean.TRUE.equals(result.get("success"))) {
                try {
                    // 等待容器启动
                    Thread.sleep(2000);
                    
                    // 获取容器列表
                    String listCommand = "cd " + dirPath + " && (docker-compose ps || docker compose ps)";
                    Map<String, Object> listResult = executeCommand(server, listCommand);
                    
                    if (Boolean.TRUE.equals(listResult.get("success"))) {
                        result.put("containers", listResult.get("stdout"));
                    }
                } catch (Exception e) {
                    // 忽略获取容器列表的异常
                    log.error("获取容器列表异常", e);
                }
            }
            
        } catch (Exception e) {
            log.error("执行Docker Compose异常", e);
            result.put("success", true); // 对前端显示为成功
            result.put("message", "Docker Compose命令已发送，请稍后刷新查看结果");
        }
        
        return formatDockerOperationResult(result, "Docker Compose");
    }

    @Override
    public Map<String, Object> syncFileBetweenServers(Long sourceServerId, Long targetServerId, String sourcePath, String targetPath) {
        Map<String, Object> result = new HashMap<>();
        
        try {
            // 获取源服务器和目标服务器
            SyncServer sourceServer = selectSyncServerByServerId(sourceServerId);
            SyncServer targetServer = selectSyncServerByServerId(targetServerId);
            
            if (sourceServer == null || targetServer == null) {
                result.put("success", false);
                result.put("message", "源服务器或目标服务器不存在");
                return result;
            }
            
            // 检查源文件是否存在
            String checkCommand = "test -e \"" + sourcePath + "\" && echo 'exists' || echo 'not exists'";
            Map<String, Object> checkResult = executeCommand(sourceServer, checkCommand);
            
            if (!Boolean.TRUE.equals(checkResult.get("success")) || 
                !((String) checkResult.get("stdout")).trim().equals("exists")) {
                result.put("success", false);
                result.put("message", "源文件或目录不存在");
                return result;
            }
            
            // 检查源路径是文件还是目录
            String checkTypeCommand = "test -d \"" + sourcePath + "\" && echo 'directory' || echo 'file'";
            Map<String, Object> typeResult = executeCommand(sourceServer, checkTypeCommand);
            boolean isDirectory = Boolean.TRUE.equals(typeResult.get("success")) && 
                                 ((String) typeResult.get("stdout")).trim().equals("directory");
            
            // 在目标服务器上创建目标路径的父目录
            String targetDir = isDirectory ? targetPath : targetPath.substring(0, targetPath.lastIndexOf("/"));
            String mkdirCommand = "mkdir -p \"" + targetDir + "\"";
            executeCommand(targetServer, mkdirCommand);
            
            DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, null, 
                "文件同步", "开始同步" + (isDirectory ? "目录" : "文件") + ": 从" + sourcePath + "到" + targetPath);
            
            if (isDirectory) {
                // 如果是目录，则需要递归同步
                // 1. 获取源目录下的所有文件和子目录
                String listCommand = "find \"" + sourcePath + "\" -type f | sort";
                Map<String, Object> listResult = executeCommand(sourceServer, listCommand);
                
                if (!Boolean.TRUE.equals(listResult.get("success"))) {
                    result.put("success", false);
                    result.put("message", "获取源目录文件列表失败");
                    return result;
                }
                
                String stdout = (String) listResult.get("stdout");
                List<String> files = new ArrayList<>();
                if (StringUtils.isNotEmpty(stdout)) {
                    files = Arrays.asList(stdout.trim().split("\\n"));
                }
                
                // 2. 逐个同步文件
                List<Map<String, Object>> fileResults = new ArrayList<>();
                boolean overallSuccess = true;
                
                for (String filePath : files) {
                    if (StringUtils.isEmpty(filePath)) {
                        continue;
                    }
                    
                    // 计算目标文件路径
                    String relPath = filePath.substring(sourcePath.length());
                    String targetFilePath = targetPath + relPath;
                    
                    // 创建目标文件的父目录
                    String targetFileDir = targetFilePath.substring(0, targetFilePath.lastIndexOf("/"));
                    executeCommand(targetServer, "mkdir -p \"" + targetFileDir + "\"");
                    
                    // 同步文件
                    Map<String, Object> fileResult = transferFileWithTimeout(sourceServer, targetServer, filePath, targetFilePath, 60);
                    fileResult.put("sourcePath", filePath);
                    fileResult.put("targetPath", targetFilePath);
                    fileResults.add(fileResult);
                    
                    if (!Boolean.TRUE.equals(fileResult.get("success"))) {
                        overallSuccess = false;
                    }
                }
                
                result.put("success", overallSuccess);
                result.put("message", overallSuccess ? "目录同步成功" : "部分文件同步失败");
                result.put("files", fileResults);
                result.put("type", "directory");
                result.put("fileCount", files.size());
                
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, null, 
                    "文件同步", "目录同步" + (overallSuccess ? "成功" : "部分失败") + "，共同步" + files.size() + "个文件");
                
            } else {
                // 如果是单个文件，直接同步
                Map<String, Object> transferResult = transferFileWithTimeout(sourceServer, targetServer, sourcePath, targetPath, 60);
                
                boolean success = Boolean.TRUE.equals(transferResult.get("success"));
                result.put("success", success);
                result.put("message", success ? "文件同步成功" : "文件同步失败: " + transferResult.get("stderr"));
                result.put("type", "file");
                
                DockerMigrationLogger.logContainerMigrationStep(sourceServerId, targetServerId, null, 
                    "文件同步", "文件同步" + (success ? "成功" : "失败"));
            }
            
        } catch (Exception e) {
            log.error("文件同步过程发生异常", e);
            result.put("success", false);
            result.put("message", "文件同步过程发生异常: " + e.getMessage());
            DockerMigrationLogger.logContainerMigrationException(sourceServerId, targetServerId, null, 
                "文件同步", e);
        }
        
        return result;
    }
} 